From d64bcb0f4ae74cd3f9fea7e5f8d7801dea674869 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 09:31:39 +0200 Subject: [PATCH 01/58] Replace setup.cfg with pyproject.toml --- pyproject.toml | 263 ++++++++++++++++++++++++++++++++++++++++++++++++- setup.cfg | 201 ------------------------------------- 2 files changed, 262 insertions(+), 202 deletions(-) delete mode 100644 setup.cfg diff --git a/pyproject.toml b/pyproject.toml index 7e7daea4..9e9a99d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,268 @@ -[build-system] +[project] +name = "hendrics" +dynamic = [ + "version" +] +description = "High ENergy Data Reduction Interface from the Command Shell" +readme = "README.rst" +authors = [ + { name = "Matteo Bachetti", email = "matteo@matteobachetti.it" } +] +license = { text = "3-clause BSD" } +requires-python = ">=3.8" +classifiers = [ + "Intended Audience :: Science/Research", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: C", + "Programming Language :: Cython", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: Implementation :: CPython", + "Topic :: Scientific/Engineering :: Astronomy", + "Topic :: Scientific/Engineering :: Physics", +] +keywords = [ + "astronomy", + "astrophysics", + "time series", + "X-ray", + "data analysis", + "black holes", + "neutron stars", + "pulsars", + "space", + "science", +] +dependencies = [ + "numpy>=1.17", + "astropy>=4.0", + "scipy>=1.1.0", + "matplotlib>=3.0,!=3.4.00,!=3.8.0", + "stingray>=2.0.0", + "tqdm", + "pyyaml" +] + + +[project.optional-dependencies] +test = [ + "pytest", + "pytest-astropy", +] +test_all = [ + "h5py", + "pandas", + "pint-pulsar", + "imageio", + "numba", + "netcdf4==1.7.0", + "scikit-image", + "statsmodels" +] +recommended = [ + "numba", + "h5py", + "pyyaml", + "statsmodels", + "pyfftw", +] +all = [ + "hendrics[recommended]", + "pandas", + "pint-pulsar", + "imageio", + "netcdf4==1.7.0", + "scikit-image", + "statsmodels" +] +docs = [ + "tomli>=1.1.0; python_version < '3.11'", + "jinja2==3.1.3", + "docutils", + "sphinx-astropy", + "nbsphinx>=0.8.3,!=0.8.8", + "nbconvert<7.14", + "pandoc", + "ipython", + "towncrier<22.12.0", +] + +[project.urls] +homepage = "https://stingray.science" +documentation = "https://hendrics.stingray.science" +repository = "https://github.com/stingraysoftware/hendrics" +[build-system] requires = ["setuptools", "setuptools_scm", "wheel"] build-backend = 'setuptools.build_meta' + +[tool.setuptools] +include-package-data = true +license-files = ["LICENSE.rst"] + +[tool.setuptools.packages.find] +include = ["hendrics*"] +exclude = ["hendrics._dev*"] +namespaces = false + +[tool.setuptools.package-data] +"*" = [ + "data/*", + "*.fits", + "*.evt", + "*.rmf", +] +"hendrics.compat" = ["datasets/*"] +"hendrics.tests" = "data/*" + +[tool.setuptools_scm] +write_to = "hendrics/_version.py" + +[tool.pytest.ini_options] +minversion = 7.0 +testpaths = [ + "hendrics", + "docs", +] +norecursedirs = [ + "docs[\\/]_build", + "docs[\\/]generated", +] +astropy_header = true +doctest_plus = "enabled" +text_file_format = "rst" +remote_data_strict = true +addopts = "--color=yes --doctest-rst" +filterwarnings = [ + "error::DeprecationWarning", + "error:.*Casting complex values:", + "ignore:.*ERFA function:", + "ignore:.*data are not sorted. :UserWarning:stingray", + "ignore:.*extended precision floating-point:RuntimeWarning:pint", + "ignore:.*pyfftw not installed:UserWarning", + "ignore:`product` is deprecated as of NumPy 1.25.0:DeprecationWarning", + "ignore:.*n_ave is below 30:UserWarning", + "ignore:.*Some error bars in the Averaged Crossspectrum:UserWarning", + "ignore:.*This platform does not support extended precision.*:RuntimeWarning:pint", + "ignore:.*function is deprecated. Set self.value.*:DeprecationWarning:pint", + "ignore:.*distutils Version classes are deprecated.*:DeprecationWarning:astropy", + "ignore:SIMON says. Errorbars on cross spectra are not thoroughly tested.:UserWarning", + "ignore:SIMON says. Stingray only uses poisson err_dist at the moment.:UserWarning", + "ignore:SIMON says. Looks like your lightcurve:UserWarning", + "ignore:Matplotlib is currently using agg, which is a:UserWarning", + "ignore:Using or importing the ABCs from 'collections':DeprecationWarning", + "ignore:elementwise == comparison failed and returning scalar instead:FutureWarning:astropy", + "ignore:unclosed file:ResourceWarning", + "ignore:numpy.ufunc size changed:RuntimeWarning", + "ignore:numpy.ndarray size changed:RuntimeWarning", + "ignore:invalid value encountered:RuntimeWarning", + "ignore:divide by zero encountered:RuntimeWarning", + "ignore:underflow encountered:RuntimeWarning", + "ignore:overflow encountered:RuntimeWarning", + "ignore:table path was not set via the path= argument; using default path:UserWarning", + "ignore:Beware! For cpds and derivatives, I assume that:UserWarning", + "ignore:SIMON says. Lightcurves have different statistics:UserWarning", + "ignore: SIMON says. Coherence is not ideal:UserWarning", + "ignore:SIMON says. The excess variance in the:UserWarning", + "ignore:SIMON says. Number of segments used in averaging:UserWarning", + "ignore:.*deprecated alias for.*:DeprecationWarning", + "ignore:.*namespace is deprecated.*:DeprecationWarning", + "ignore:.*Matplotlib 3.8", +] + +[tool.towncrier] + package = "hendrics" + filename = "CHANGELOG.rst" + directory = "docs/changes/" + issue_format = "`#{issue} `__" + title_format = "v{version} ({project_date})" + underlines = "-^" + + [[tool.towncrier.type]] + directory = "breaking" + name = "Breaking Changes" + showcontent = true + + [[tool.towncrier.type]] + directory = "deprecation" + name = "Deprecations" + showcontent = true + + [[tool.towncrier.type]] + directory = "removal" + name = "Removals" + showcontent = true + + [[tool.towncrier.type]] + directory = "feature" + name = "New Features" + showcontent = true + + [[tool.towncrier.type]] + directory = "bugfix" + name = "Bug Fixes" + showcontent = true + + [[tool.towncrier.type]] + directory = "doc" + name = "Documentation" + showcontent = true + + [[tool.towncrier.type]] + directory = "trivial" + name = "Internal Changes" + showcontent = true + +[tool.black] +line-length = 100 + +[tool.coverage] + + [tool.coverage.run] + omit = [ + "hendrics/_astropy_init*", + "hendrics/conftest.py", + "hendrics/*setup_package*", + "hendrics/tests/*", + "hendrics/compat/*", + "hendrics/*/tests/*", + "hendrics/extern/*", + "hendrics/version*", + "*/hendrics/_astropy_init*", + "*/hendrics/conftest.py", + "*/hendrics/*setup_package*", + "*/hendrics/tests/*", + "*/hendrics/*/tests/*", + "*/hendrics/extern/*", + "*/hendrics/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_", + ] + +[tool.flake8] +max-line-length = 100 +exclude = ".git,__pycache__,docs/source/conf.py,old,build,dist,*.egg-info" +extend-ignore = "E203, W503, W605" + +[tool.pycodestyle] +max-line-length = 100 +exclude = ".git,__pycache__,docs/source/conf.py,old,build,dist,*.egg-info" diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 5196b999..00000000 --- a/setup.cfg +++ /dev/null @@ -1,201 +0,0 @@ -[metadata] -name = hendrics -description = "High ENergy Data Reduction Interface from the Command Shell" -long_description = file: README.rst -author = Matteo Bachetti -author_email = matteo@matteobachetti.it -license = BSD -license_file: LICENSE.rst -url = https://hendrics.readthedocs.io -edit_on_github = True -github_project = StingraySoftware/HENDRICS -keywords = astronomy, astrophysics, space, science, timeseries, timing -classifiers = - Intended Audience :: Science/Research - License :: OSI Approved :: BSD License - Operating System :: OS Independent - Programming Language :: C - Programming Language :: Cython - Programming Language :: Python :: 3 - Programming Language :: Python :: Implementation :: CPython - Topic :: Scientific/Engineering :: Astronomy - Topic :: Scientific/Engineering :: Physics - -[options] -zip_safe = False -packages = find: -python_requires = >=3.8 -setup_requires = setuptools_scm -install_requires = - numpy - astropy - scipy - stingray>=2.0.0 - matplotlib !=3.8.0 - tqdm - pyyaml - -[options.extras_require] -all = - h5py - pandas - pint-pulsar - imageio - numba - netcdf4==1.7.0 - scikit-image - statsmodels -test = - pytest-astropy -docs = - sphinx-astropy - sphinx-toolbox - -[options.entry_points] -console_scripts = - HEN2xspec = hendrics.save_as_xspec:main - HENaccelsearch = hendrics.efsearch:main_accelsearch - HENbaseline = hendrics.lcurve:baseline_main - HENbinary = hendrics.binary:main_presto - HENcalibrate = hendrics.calibrate:main - HENcolors = hendrics.colors:main - HENcreategti = hendrics.create_gti:main - HENdeorbit = hendrics.fold:main_deorbit - HENdumpdyn = hendrics.fspec:dumpdyn_main - HENefsearch = hendrics.efsearch:main_efsearch - HENexcvar = hendrics.exvar:main - HENexposure = hendrics.exposure:main - HENfake = hendrics.fake:main - HENfiltevents = hendrics.io:main_filter_events - HENfold = hendrics.fold:main_fold - HENfspec = hendrics.fspec:main - HENjoinevents = hendrics.read_events:main_join - HENlags = hendrics.timelags:main - HENlcurve = hendrics.lcurve:main - HENmodel = hendrics.modeling:main_model - HENphaseogram = hendrics.phaseogram:main_phaseogram - HENphasetag = hendrics.phasetag:main_phasetag - HENplot = hendrics.plot:main - HENpowercolors = hendrics.power_colors:main - HENreadevents = hendrics.read_events:main - HENreadfile = hendrics.io:main - HENrebin = hendrics.rebin:main -; HENregfilter = hendrics.io:main_regfilter - HENscramble = hendrics.fake:main_scramble - HENscrunchlc = hendrics.lcurve:scrunch_main - HENsplitevents = hendrics.read_events:main_splitevents - HENsumfspec = hendrics.sum_fspec:main - HENvarenergy = hendrics.varenergy:main - HENz2vspf = hendrics.efsearch:main_z2vspf - HENzsearch = hendrics.efsearch:main_zsearch - -[options.package_data] -hendrics.tests = data/* -hendrics.compat = datasets/* -* = *.fits, *.evt, *.rmf - -;[config.logging_helper] -;# Threshold for the logging messages. Logging messages that are less severe -;# than this level will be ignored. The levels are 'DEBUG', 'INFO', 'WARNING', -;# 'ERROR' -;log_level = 'INFO' -;# Whether to use color for the level names -;use_color = True -;# Whether to log warnings.warn calls -;log_warnings = True -;# Whether to log exceptions before raising them -;log_exceptions = True -;# Whether to always log messages to a log file -;log_to_file = True -;# The file to log messages to -;log_file_path = '~/.HENDRICS.log' -;# Threshold for logging messages to log_file_path -;log_file_level = 'INFO' -;# Format for log file entries -;#log_file_format = '%(asctime)s, %(origin)s, %(levelname)s, %(message)s' - -[tool:pytest] -testpaths = "hendrics" "docs" -astropy_header = true -doctest_plus = enabled -text_file_format = rst -addopts = --doctest-rst -filterwarnings = - error::DeprecationWarning - error:.*Casting complex values: - ignore:.*ERFA function: - ignore:.*data are not sorted. :UserWarning:stingray - ignore:.*extended precision floating-point:RuntimeWarning:pint - ignore:.*pyfftw not installed:UserWarning - ignore:`product` is deprecated as of NumPy 1.25.0:DeprecationWarning - ignore:.*n_ave is below 30:UserWarning - ignore:.*Some error bars in the Averaged Crossspectrum:UserWarning - ignore:.*This platform does not support extended precision.*:RuntimeWarning:pint - ignore:.*function is deprecated. Set self.value.*:DeprecationWarning:pint - ignore:.*distutils Version classes are deprecated.*:DeprecationWarning:astropy - ignore:SIMON says. Errorbars on cross spectra are not thoroughly tested.:UserWarning - ignore:SIMON says. Stingray only uses poisson err_dist at the moment.:UserWarning - ignore:SIMON says. Looks like your lightcurve:UserWarning - ignore:Matplotlib is currently using agg, which is a:UserWarning - ignore:Using or importing the ABCs from 'collections':DeprecationWarning - ignore:elementwise == comparison failed and returning scalar instead:FutureWarning:astropy - ignore:unclosed file:ResourceWarning - ignore:numpy.ufunc size changed:RuntimeWarning - ignore:numpy.ndarray size changed:RuntimeWarning - ignore:invalid value encountered:RuntimeWarning - ignore:divide by zero encountered:RuntimeWarning - ignore:underflow encountered:RuntimeWarning - ignore:overflow encountered:RuntimeWarning - ignore:table path was not set via the path= argument; using default path:UserWarning - ignore:Beware! For cpds and derivatives, I assume that:UserWarning - ignore:SIMON says. Lightcurves have different statistics:UserWarning - ignore: SIMON says. Coherence is not ideal:UserWarning - ignore:SIMON says. The excess variance in the:UserWarning - ignore:SIMON says. Number of segments used in averaging:UserWarning - ignore:.*deprecated alias for.*:DeprecationWarning - ignore:.*namespace is deprecated.*:DeprecationWarning - ignore:.*Matplotlib 3.8 - -[coverage:run] -omit = - hendrics/_astropy_init* - hendrics/conftest.py - hendrics/*setup_package* - hendrics/tests/* - hendrics/compat/* - hendrics/*/tests/* - hendrics/extern/* - hendrics/version* - */hendrics/_astropy_init* - */hendrics/conftest.py - */hendrics/*setup_package* - */hendrics/tests/* - */hendrics/*/tests/* - */hendrics/extern/* - */hendrics/version* - -[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 assertions - 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_ - - -[pycodestyle] -max-line-length = 100 -exclude = extern,*parsetab.py,*lextab.py,test_*.py,__*.py - - -[flake8] -max-line-length = 100 -exclude = extern,*parsetab.py,*lextab.py,test_*.py,__*.py From 0999f27ba10e2f3d8c07b8bddddcafbdd7a6fbee Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 09:43:56 +0200 Subject: [PATCH 02/58] Add ruff to pre-commit stuff --- .pre-commit-config.yaml | 108 +++++++++++++++++++++ .ruff.toml | 210 ++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 41 ++++++++ 3 files changed, 359 insertions(+) create mode 100644 .pre-commit-config.yaml create mode 100644 .ruff.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..f9327d2f --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,108 @@ +ci: + autofix_prs: false + autoupdate_schedule: 'monthly' + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: check-added-large-files + args: ["--enforce-all", "--maxkb=300"] + exclude: + # Prevent giant files from being committed. + - id: check-case-conflict + # Check for files with names that would conflict on a case-insensitive + # filesystem like MacOS HFS+ or Windows FAT. + - id: check-json + # Attempts to load all json files to verify syntax. + - id: check-merge-conflict + # Check for files that contain merge conflict strings. + - id: check-symlinks + # Checks for symlinks which do not point to anything. + - id: check-toml + # Attempts to load all TOML files to verify syntax. + - id: check-xml + # Attempts to load all xml files to verify syntax. + - id: check-yaml + # Attempts to load all yaml files to verify syntax. + exclude: ".*(.github.*)$" + - id: detect-private-key + # Checks for the existence of private keys. + - id: end-of-file-fixer + # Makes sure files end in a newline and only a newline. + exclude: ".*(data.*|extern.*|licenses.*|_static.*|_parsetab.py)$" + # - id: fix-encoding-pragma # covered by pyupgrade + - id: trailing-whitespace + # Trims trailing whitespace. + exclude_types: [python] # Covered by Ruff W291. + exclude: ".*(data.*|extern.*|licenses.*|_static.*)$" + + - repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.10.0 + hooks: + - id: rst-directive-colons + # Detect mistake of rst directive not ending with double colon. + - id: rst-inline-touching-normal + # Detect mistake of inline code touching normal text in rst. + - id: text-unicode-replacement-char + # Forbid files which have a UTF-8 Unicode replacement character. + + - repo: https://github.com/codespell-project/codespell + rev: v2.3.0 + hooks: + - id: codespell + args: ["--write-changes"] + additional_dependencies: + - tomli + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.6.9 + hooks: + - id: ruff + args: ["--fix", "--show-fixes"] + - id: ruff-format + + - repo: https://github.com/scientific-python/cookie + rev: 2024.08.19 + hooks: + - id: sp-repo-review + + - repo: https://github.com/PyCQA/docformatter + # using an untagged rev for forward compatibility with pre-commit 4.0 + # see https://github.com/PyCQA/docformatter/issues/289 + # This should be changed back to a tag when (>1.7.5) is released + rev: 06907d0267368b49b9180eed423fae5697c1e909 + hooks: + - id: docformatter + additional_dependencies: [tomli] + args: [--in-place, --config, ./pyproject.toml] + exclude: | + (?x)( + test.*\.py | + hendrics/__init__\.py | + hendrics/_dev/ | + hendrics/conftest\.py | + astropy/version\.py | + docs/ | + examples/ + ) + + - repo: local + hooks: + - id: changelogs-rst + name: changelog filenames + language: fail + entry: >- + changelog files must be named /####.(bugfix|feature|api|perf).rst + or ####.other.rst (in the root directory only) + exclude: >- + ^docs/changes/[\w\.]+/(\d+\.(bugfix|feature|api|perf)(\.\d)?.rst|.gitkeep) + files: ^docs/changes/[\w\.]+/ + - id: changelogs-rst-other + name: changelog filenames for other category + language: fail + entry: >- + only "other" changelog files must be placed in the root directory + exclude: >- + ^docs/changes/(\d+\.other.rst|README.rst|template.rst) + files: ^docs/changes/\d+.\w+.rst \ No newline at end of file diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 00000000..50fd16f2 --- /dev/null +++ b/.ruff.toml @@ -0,0 +1,210 @@ +extend = "pyproject.toml" +lint.ignore = [ + # NOTE: to find a good code to fix, run: + # ruff --select="ALL" --statistics astropy/ + + # flake8-annotations (ANN) : static typing + "ANN001", # Function argument without type annotation + "ANN003", # `**kwargs` without type annotation + "ANN202", # Private function without return type annotation + "ANN401", # Use of `Any` type + + # flake8-unused-arguments (ARG) + "ARG001", # unused-function-argument + "ARG002", # unused-method-argument + "ARG003", # unused-class-method-argument + "ARG004", # unused-static-method-argument + "ARG005", # unused-lambda-argument + + # flake8-bugbear (B) + "B006", # MutableArgumentDefault + "B007", # UnusedLoopControlVariable + "B023", # FunctionUsesLoopVariable + "B028", # No-explicit-stacklevel + "B904", # RaiseWithoutFromInsideExcept + "B905", # ZipWithoutExplicitStrict + + # flake8-blind-except (BLE) + "BLE001", # blind-except + + # mccabe (C90) : code complexity + # TODO: configure maximum allowed complexity. + "C901", # McCabeComplexity + + # pydocstyle (D) + # Missing Docstrings + "D100", # undocumented-public-module + "D101", # undocumented-public-class + "D103", # undocumented-public-function + "D104", # undocumented-public-package + "D205", # blank-line-after-summary + # Quotes Issues + "D300", # triple-single-quotes + "D301", # escape-sequence-in-docstring + # Docstring Content Issues + "D403", # first-line-capitalized + "D404", # docstring-starts-with-this + "D401", # non-imperative-mood. + "D414", # empty-docstring-section + "D419", # docstring is empty + + # flake8-datetimez (DTZ) + "DTZ001", # call-datetime-without-tzinfo + "DTZ005", # call-datetime-now-without-tzinfo + + # pycodestyle (E, W) + "E501", # line-too-long + "E721", # type-comparison + "E731", # lambda-assignment + + # flake8-errmsg (EM) : nicer error tracebacks + "EM101", # raw-string-in-exception + "EM102", # f-string-in-exception + "EM103", # dot-format-in-exception + + # eradicate (ERA) + # NOTE: be careful that developer notes are kept. + "ERA001", # commented-out-code + + # flake8-executable (EXE) + "EXE002", # shebang-missing-executable-file + + # Pyflakes (F) + "F841", # unused-variable + + # flake8-boolean-trap (FBT) : boolean flags should be kwargs, not args + # NOTE: a good thing to fix, but changes API. + "FBT001", # boolean-positional-arg-in-function-definition + "FBT002", # boolean-default-value-in-function-definition + "FBT003", # boolean-positional-value-in-function-call + + # flake8-fixme (FIX) + "FIX001", # Line contains FIXME. this should be fixed or at least FIXME replaced with TODO + "FIX004", # Line contains HACK. replace HACK with NOTE. + + # pep8-naming (N) + # NOTE: some of these can/should be fixed, but this changes the API. + "N801", # invalid-class-name + "N802", # invalid-function-name + "N803", # invalid-argument-name + "N804", # invalid-first-argument-name-for-class-method + "N805", # invalid-first-argument-name-for-method + "N807", # dunder-function-name + "N813", # camelcase-imported-as-lowercase + "N815", # mixed-case-variable-in-class-scope + "N816", # mixed-case-variable-in-global-scope + "N818", # error-suffix-on-exception-name + + # NumPy-specific rules (NPY) + "NPY002", # Replace legacy `np.random.rand` call with `np.random.Generator` (2023-05-03) + + # Perflint (PERF) + "PERF203", # `try`-`except` within a loop incurs performance overhead + "PERF401", # Use a list comprehension to create a transformed list + + # Pylint (PLC, PLE, PLR, PLW) + "PLE0101", # return-in-init + "PLR0124", # Name compared with itself + "PLR0402", # ConsiderUsingFromImport + "PLR0912", # too-many-branches + "PLR0913", # too-many-args + "PLR0915", # too-many-statements + "PLR1714", # Consider merging multiple comparisons + "PLR2004", # MagicValueComparison + "PLR5501", # collapsible-else-if + "PLW0603", # global-statement + "PLW2901", # redefined-loop-name + + # flake8-pytest-style (PT) + "PT003", # pytest-extraneous-scope-function + "PT004", # pytest-missing-fixture-name-underscore # deprecated in ruff 0.6.0 + "PT006", # pytest-parametrize-names-wrong-type + "PT007", # pytest-parametrize-values-wrong-type + "PT011", # pytest-raises-too-broad + "PT012", # pytest-raises-with-multiple-statements + "PT017", # pytest-assert-in-exceptinstead + "PT018", # pytest-composite-assertion + "PT022", # pytest-useless-yield-fixture + + # flake8-return (RET) + "RET501", # unnecessary-return-none + "RET502", # implicit-return-value + "RET503", # implicit-return + "RET504", # unnecessary-assign + "RET507", # superfluous-else-continue + + # flake8-raise (RSE) + "RSE102", # unnecessary-paren-on-raise-exception + + # Ruff-specific rules (RUF) + "RUF001", # ambiguous-unicode-character-string + "RUF002", # ambiguous-unicode-character-docstring + "RUF010", # use conversion in f-string + "RUF012", # Mutable class attributes should be annotated with `typing.ClassVar` + + # flake8-bandit (S) + "S101", # Use of `assert` detected + "S105", # hardcoded-password-string + "S110", # try-except-pass + "S112", # try-except-continue + "S301", # suspicious-pickle-usage + "S307", # Use of possibly insecure function; consider using `ast.literal_eval` + "S311", # suspicious-non-cryptographic-randomness + "S324", # hashlib-insecure-hash-function + "S506", # UnsafeYAMLLoad + "S310", # Suspicious-url-open-usage + "S603", # `subprocess` call: check for execution of untrusted input + "S607", # Starting a process with a partial executable path + + # flake8-simplify (SIM) + "SIM102", # NestedIfStatements + "SIM105", # UseContextlibSuppress + "SIM108", # UseTernaryOperator + "SIM114", # if-with-same-arms + "SIM115", # OpenFileWithContextHandler + "SIM117", # MultipleWithStatements + "SIM118", # KeyInDict + "SIM201", # NegateEqualOp + "SIM300", # yoda condition + + # flake8-print (T20) + "T201", # PrintUsed + + # flake8-todos (TD) + "TD001", # Invalid TODO tag + "TD003", # Missing issue link on the line following this TODO + "TD004", # Missing colon in TODO + "TD007", # Missing space after colon in TODO + + # tryceratops (TRY) + "TRY002", # raise-vanilla-class + "TRY003", # raise-vanilla-args + "TRY004", # prefer-type-error + "TRY201", # verbose-raise + "TRY301", # raise-within-try + + # pyupgrade (UP) + "UP038", # isinstance using union separators. The code is slower as of Python 3.11-3.12 + + # flake8-quotes (Q) + "Q000", # use double quotes +] +lint.unfixable = [ + "E711" # NoneComparison. Hard to fix b/c numpy has it's own None. +] + +[lint.extend-per-file-ignores] +"__init__.py" = ["E402", "F401", "F403"] +"test_*.py" = [ + "PTH", # all flake8-use-pathlib + "RUF015", # Prefer next({iterable}) over single element slice +] +# TODO: fix these, on a per-subpackage basis. +# When a general exclusion is being fixed, but it affects many subpackages, it +# is better to fix for subpackages individually. The general exclusion should be +# copied to these subpackage sections and fixed there. +# "astropy/config/*" = [] +# "astropy/constants/*" = [ +# "N817", # camelcase-imported-as-acronym +# "RET505", # superfluous-else-return +# ] diff --git a/pyproject.toml b/pyproject.toml index 9e9a99d1..459d72e4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -266,3 +266,44 @@ extend-ignore = "E203, W503, W605" [tool.pycodestyle] max-line-length = 100 exclude = ".git,__pycache__,docs/source/conf.py,old,build,dist,*.egg-info" + +[tool.ruff.lint.extend-per-file-ignores] +"setup.py" = ["INP001"] # Part of configuration, not a package. +".github/workflows/*.py" = ["INP001"] +"astropy/modeling/models/__init__.py" = ["F405"] +"astropy/utils/decorators.py" = [ + "D214", "D215", # keep Examples section indented. + "D411", # sphinx treats spaced example sections as real sections +] +"test_*.py" = [ + "ANN201", # Public function without return type annotation + "B018", # UselessExpression + "D", # pydocstyle + "S101", # Use of assert detected +] +".pyinstaller/*.py" = ["INP001"] # Not a package. +"conftest.py" = ["INP001"] # Part of configuration, not a package. +"docs/*.py" = [ + "INP001", # implicit-namespace-package. The examples are not a package. +] +"examples/*.py" = [ + "E402", # Imports are done as needed. + "INP001", # implicit-namespace-package. The examples are not a package. + "T203" # pprint found +] + +[tool.ruff.lint.flake8-annotations] +ignore-fully-untyped = true +mypy-init-return = true + +[tool.ruff.lint.flake8-comprehensions] +allow-dict-calls-with-keyword-arguments = true + +[tool.ruff.lint.flake8-type-checking] +exempt-modules = [] + +[tool.ruff.lint.isort] +known-first-party = ["astropy", "extension_helpers"] + +[tool.ruff.lint.pydocstyle] +convention = "numpy" From 6cd1baa2418b741f67a3d541b21b4a0e4725e295 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 09:46:27 +0200 Subject: [PATCH 03/58] Add ruff lines --- pyproject.toml | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 459d72e4..eb9e6cce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -267,6 +267,84 @@ extend-ignore = "E203, W503, W605" max-line-length = 100 exclude = ".git,__pycache__,docs/source/conf.py,old,build,dist,*.egg-info" +[tool.ruff] +lint.select = ["ALL"] +exclude=[ + "astropy/extern/*", + "*_parsetab.py", + "*_lextab.py" +] +lint.ignore = [ # NOTE: non-permanent exclusions should be added to `.ruff.toml` instead. + + # flake8-builtins (A) : shadowing a Python built-in. + # New ones should be avoided and is up to maintainers to enforce. + "A00", + + # flake8-annotations (ANN) + "ANN101", # No annotation for `self`. + "ANN102", # No annotation for `cls`. + + # flake8-bugbear (B) + "B008", # FunctionCallArgumentDefault + + # flake8-commas (COM) + "COM812", # TrailingCommaMissing + "COM819", # TrailingCommaProhibited + + # pydocstyle (D) + # Missing Docstrings + "D102", # Missing docstring in public method. Don't check b/c docstring inheritance. + "D105", # Missing docstring in magic method. Don't check b/c class docstring. + # Whitespace Issues + "D200", # FitsOnOneLine + # Docstring Content Issues + "D410", # BlankLineAfterSection. Using D412 instead. + "D400", # EndsInPeriod. NOTE: might want to revisit this. + + # pycodestyle (E, W) + "E711", # NoneComparison (see unfixable) + "E741", # AmbiguousVariableName. Physics variables are often poor code variables + + # flake8-fixme (FIX) + "FIX002", # Line contains TODO | notes for improvements are OK iff the code works + + # ISC001 shouldn't be used with ruff format + # https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules + "ISC001", + + # pep8-naming (N) + "N803", # invalid-argument-name. Physics variables are often poor code variables + "N806", # non-lowercase-variable-in-function. Physics variables are often poor code variables + + # pandas-vet (PD) + "PD", + + # pylint (PLR and PLW) + "PLR1730", # if-stmt-min-max (not always clearer, and sometimes slower) + "PLW0642", # self-or-cls-assignment (occasionally desirable, very rarely a mistake) + + # flake8-use-pathlib (PTH) + "PTH123", # builtin-open (not worth creating a Path object, builtin open is fine) + + # flake8-simplify (SIM) + "SIM103", # needless-bool (cannot be safely applied in all contexts (np.True_ is not True)) + + # flake8-self (SLF) + "SLF001", # private member access + + # flake8-todos (TD) + "TD002", # Missing author in TODO + + # flake8-return (RET) + # RET can sometimes help find places where refactoring is very helpful, + # but enforcing it everywhere might create undesirable churn + "RET505", # superfluous-else-return + "RET506", # superfluous-else-raise + + # Ruff-specific rules (RUF) + "RUF005", # unpack-instead-of-concatenating-to-collection-literal -- it's not clearly faster. +] + [tool.ruff.lint.extend-per-file-ignores] "setup.py" = ["INP001"] # Part of configuration, not a package. ".github/workflows/*.py" = ["INP001"] From 2138b32e124b97ae923e2456014543dae763023e Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 10:55:57 +0200 Subject: [PATCH 04/58] Configure ruff --- .pre-commit-config.yaml | 4 +-- pyproject.toml | 57 ++++++++++++++++++++++++++++++++--------- tox.ini | 10 +++++--- 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f9327d2f..211e730a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,7 +8,7 @@ repos: hooks: - id: check-added-large-files args: ["--enforce-all", "--maxkb=300"] - exclude: + # exclude: # Prevent giant files from being committed. - id: check-case-conflict # Check for files with names that would conflict on a case-insensitive @@ -105,4 +105,4 @@ repos: only "other" changelog files must be placed in the root directory exclude: >- ^docs/changes/(\d+\.other.rst|README.rst|template.rst) - files: ^docs/changes/\d+.\w+.rst \ No newline at end of file + files: ^docs/changes/\d+.\w+.rst diff --git a/pyproject.toml b/pyproject.toml index eb9e6cce..e829d103 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -216,8 +216,6 @@ filterwarnings = [ name = "Internal Changes" showcontent = true -[tool.black] -line-length = 100 [tool.coverage] @@ -258,21 +256,13 @@ line-length = 100 "def _ipython_key_completions_", ] -[tool.flake8] -max-line-length = 100 -exclude = ".git,__pycache__,docs/source/conf.py,old,build,dist,*.egg-info" -extend-ignore = "E203, W503, W605" - -[tool.pycodestyle] -max-line-length = 100 -exclude = ".git,__pycache__,docs/source/conf.py,old,build,dist,*.egg-info" - [tool.ruff] lint.select = ["ALL"] exclude=[ "astropy/extern/*", "*_parsetab.py", - "*_lextab.py" + "*_lextab.py", + "*.svg" ] lint.ignore = [ # NOTE: non-permanent exclusions should be added to `.ruff.toml` instead. @@ -385,3 +375,46 @@ known-first-party = ["astropy", "extension_helpers"] [tool.ruff.lint.pydocstyle] convention = "numpy" + +[tool.codespell] +skip = """ + *.cff, + */data/*, + *extern/*, + hendrics/CITATION, + docs/credits.rst, + *_lextab.py, + *_parsetab.py, +""" +# The following list of words for codespell to ignore may contain some +# misspellings that should be revisited and fixed in the future. +ignore-words-list = """ + aas, + ans, + clen, + coo, + datas, + ded, + dum, + fo, + hel, + lightyear, + livetime, + lond, + nax, + nd, + ned, + nin, + numer, + observe.length, + precess, + precessed, + precesses, + precessing, + pres, + som, + splitted, + stil, + te, + wirth, +""" diff --git a/tox.ini b/tox.ini index f939b668..c912c9d6 100644 --- a/tox.ini +++ b/tox.ini @@ -91,10 +91,12 @@ commands = [testenv:codestyle] skip_install = true -changedir = . -description = check code style, e.g. with flake8 -deps = flake8 -commands = flake8 hendrics --count --max-line-length=100 --select=E101,W191,W291,W292,W293,W391,E111,E112,E113,E30,E502,E722,E901,E902,E999,F822,F823 +description = Run all style and file checks with pre-commit +deps = + pre-commit +commands = + pre-commit install-hooks + pre-commit run {posargs:--color always --all-files --show-diff-on-failure} [testenv:black] skip_install = true From e9b0f1ecda157ac3afaf955d7959be169fb362ac Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 10:57:06 +0200 Subject: [PATCH 05/58] Cleanup --- .pep8speaks.yml | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100644 .pep8speaks.yml diff --git a/.pep8speaks.yml b/.pep8speaks.yml deleted file mode 100644 index d720e7ce..00000000 --- a/.pep8speaks.yml +++ /dev/null @@ -1,30 +0,0 @@ -# File : .pep8speaks.yml - -scanner: - diff_only: True # If False, the entire file touched by the Pull Request is scanned for errors. If True, only the diff is scanned. - linter: pycodestyle # Other option is flake8 - -pycodestyle: # Same as scanner.linter value. Other option is flake8 - max-line-length: 100 # Default is 79 in PEP 8 - ignore: # Errors and warnings to ignore - - W503 # line break before binary operator - - W504 # line break after binary operator - - E402 # module level import not at top of file - - E731 # do not assign a lambda expression, use a def - - C406 # Unnecessary list literal - rewrite as a dict literal. - - E741 # ambiguous variable name - - E203 # whitespace before ':' - -no_blank_comment: True # If True, no comment is made on PR without any errors. -descending_issues_order: False # If True, PEP 8 issues in message will be displayed in descending order of line numbers in the file - -message: # Customize the comment made by the bot - opened: # Messages when a new PR is submitted - header: "Hello @{name}! Thanks for opening this PR. " - # The keyword {name} is converted into the author's username - footer: "Do see the [Hitchhiker's guide to code style](https://goo.gl/hqbW4r)" - # The messages can be written as they would over GitHub - updated: # Messages when new commits are added to the PR - header: "Hello @{name}! Thanks for updating this PR. " - footer: "" # Why to comment the link to the style guide everytime? :) - no_errors: "There are currently no PEP 8 issues detected in this Pull Request. Cheers! :beers: " \ No newline at end of file From f97460da9072ef19849dba7275f08d6d907e7ca1 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 11:02:28 +0200 Subject: [PATCH 06/58] Add _version to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6b369bbc..06e33539 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ __pycache__ # Other generated files */version.py +*/_version.py */cython_version.py htmlcov .coverage From c37d817db6db9143e1d194f86d03e4397dbd0cd8 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 11:23:59 +0200 Subject: [PATCH 07/58] Fix no newline --- CITATION | 1 - MANIFEST.in | 2 +- notebooks/deadtime_model_zhang.py | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/CITATION b/CITATION index fd417b42..bdf8fed4 100644 --- a/CITATION +++ b/CITATION @@ -42,4 +42,3 @@ archivePrefix = "arXiv", adsurl = {https://adsabs.harvard.edu/abs/2015ApJ...800..109B}, adsnote = {Provided by the SAO/NASA Astrophysics Data System} } - diff --git a/MANIFEST.in b/MANIFEST.in index c76339e0..fd3524ad 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -22,4 +22,4 @@ recursive-include static * prune docs/_build prune build -global-exclude *.pyc *.o \ No newline at end of file +global-exclude *.pyc *.o diff --git a/notebooks/deadtime_model_zhang.py b/notebooks/deadtime_model_zhang.py index 0bb633c5..f22c1625 100644 --- a/notebooks/deadtime_model_zhang.py +++ b/notebooks/deadtime_model_zhang.py @@ -156,4 +156,3 @@ def check_pds_rate(td, tb, N=100): plt.xlabel(r'$\tau$') plt.ylabel(r'Max($P_j$)') plt.loglog() - From ab2f536dc446ba43dfba66a60fad1c89fe471b1e Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 11:24:44 +0200 Subject: [PATCH 08/58] Fix trailing newline --- docs/scripts/cli.rst | 2 -- docs/tutorials/pulsars.rst | 1 - 2 files changed, 3 deletions(-) diff --git a/docs/scripts/cli.rst b/docs/scripts/cli.rst index 7ff41412..0ba8e5ff 100644 --- a/docs/scripts/cli.rst +++ b/docs/scripts/cli.rst @@ -1216,5 +1216,3 @@ HENzsearch --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; default:WARNING) --debug set DEBUG logging level - - diff --git a/docs/tutorials/pulsars.rst b/docs/tutorials/pulsars.rst index 158caf7d..d62a6761 100644 --- a/docs/tutorials/pulsars.rst +++ b/docs/tutorials/pulsars.rst @@ -172,4 +172,3 @@ Measuring frequency derivatives interactively
- From d7e8d597eccade0128f0b1e8e8d881fb9a44ae17 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 11:32:43 +0200 Subject: [PATCH 09/58] configure codespell --- pyproject.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e829d103..330a5eb2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -385,6 +385,9 @@ skip = """ docs/credits.rst, *_lextab.py, *_parsetab.py, + *.svg, + docs/scripts/cli.rst, + *.ipynb, """ # The following list of words for codespell to ignore may contain some # misspellings that should be revisited and fixed in the future. @@ -406,7 +409,7 @@ ignore-words-list = """ ned, nin, numer, - observe.length, + observ.length, precess, precessed, precesses, From d6126895e05b3a2c05b8ffd76c53da3a4cca1ce0 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 11:32:54 +0200 Subject: [PATCH 10/58] Fix wording --- docs/tutorials/quicklook.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/quicklook.rst b/docs/tutorials/quicklook.rst index 554b3b85..1bca2582 100644 --- a/docs/tutorials/quicklook.rst +++ b/docs/tutorials/quicklook.rst @@ -34,7 +34,7 @@ of intermediate products until the final result. For example: with a given bin time. Only if starting from a calibrated event list, the light curve can be obtained by specifying an energy range, otherwise only the PI channel - filtering is avaiable. + filtering is available. 4. (optional) **summed light curves** if we want to join events from multiple instruments, or just from different observing times From 1ffacb5418612fce8a8c2f4013d9f4a79efd8f45 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 11:35:07 +0200 Subject: [PATCH 11/58] Fix ignored spelling in pyproject --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 330a5eb2..ceb5666c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -388,6 +388,7 @@ skip = """ *.svg, docs/scripts/cli.rst, *.ipynb, + pyproject.toml, """ # The following list of words for codespell to ignore may contain some # misspellings that should be revisited and fixed in the future. From 8200c1523a4d22b612384fcd48e2b4e577cad349 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 11:46:00 +0200 Subject: [PATCH 12/58] Fix wording and spacing --- docs/scripts/cli.rst | 8 +-- hendrics/base.py | 2 +- hendrics/create_gti.py | 2 +- hendrics/efsearch.py | 122 +++++++++++------------------------------ hendrics/lcurve.py | 4 +- hendrics/varenergy.py | 2 +- 6 files changed, 40 insertions(+), 100 deletions(-) diff --git a/docs/scripts/cli.rst b/docs/scripts/cli.rst index 0ba8e5ff..62793b01 100644 --- a/docs/scripts/cli.rst +++ b/docs/scripts/cli.rst @@ -308,10 +308,10 @@ HENefsearch Size of the event list segment to use (default None, implying the whole observation) --step STEP Step size of the frequency axis. Defaults to - 1/oversample/observ.length. + 1/oversample/obs_length. --oversample OVERSAMPLE Oversampling factor - frequency resolution improvement - w.r.t. the standard FFT's 1/observ.length. + w.r.t. the standard FFT's 1/obs_length. --fast Use a faster folding algorithm. It automatically searches for the first spin derivative using an optimized step.This option ignores expocorr, @@ -1183,10 +1183,10 @@ HENzsearch Size of the event list segment to use (default None, implying the whole observation) --step STEP Step size of the frequency axis. Defaults to - 1/oversample/observ.length. + 1/oversample/obs_length. --oversample OVERSAMPLE Oversampling factor - frequency resolution improvement - w.r.t. the standard FFT's 1/observ.length. + w.r.t. the standard FFT's 1/obs_length. --fast Use a faster folding algorithm. It automatically searches for the first spin derivative using an optimized step.This option ignores expocorr, diff --git a/hendrics/base.py b/hendrics/base.py index cedf4fde..9a23d4ba 100644 --- a/hendrics/base.py +++ b/hendrics/base.py @@ -1001,7 +1001,7 @@ def histogram(*args, **kwargs): def touch(fname): - """Mimick the same shell command. + """Mimic the same shell command. Examples -------- diff --git a/hendrics/create_gti.py b/hendrics/create_gti.py index ce0dd476..b031f3ec 100644 --- a/hendrics/create_gti.py +++ b/hendrics/create_gti.py @@ -148,7 +148,7 @@ def main(args=None): "--create-only", default=False, action="store_true", - help="If specified, creates GTIs withouth applying" + help="If specified, creates GTIs without applying" + "them to files (Default: False)", ) diff --git a/hendrics/efsearch.py b/hendrics/efsearch.py index c55ef7ae..caf3c56b 100644 --- a/hendrics/efsearch.py +++ b/hendrics/efsearch.py @@ -224,9 +224,7 @@ def decide_binary_parameters( ] df = 1 / length - log.info( - "Recommended frequency steps: {}".format(int(np.diff(freq_range)[0] // df + 1)) - ) + log.info("Recommended frequency steps: {}".format(int(np.diff(freq_range)[0] // df + 1))) while count < NMAX: # In any case, only the first loop deletes the file if count > 0: @@ -246,9 +244,7 @@ def decide_binary_parameters( Omegas = np.random.uniform(omega_range[0], omega_range[1], nOmega) for Omega in Omegas: - block_of_data.append( - [freq, fdot, X, TWOPI / Omega, False, 0.0, 0.0, 0.0] - ) + block_of_data.append([freq, fdot, X, TWOPI / Omega, False, 0.0, 0.0, 0.0]) df = pd.DataFrame(block_of_data, columns=columns) _save_df_to_csv(df, csv_file, reset=reset) @@ -291,12 +287,8 @@ def folding_orbital_search( for T0 in T0s: # one iteration new_values = times - X * np.sin(2 * np.pi * (times - T0) / Porb) - new_values = new_values - X * np.sin( - 2 * np.pi * (new_values - T0) / Porb - ) - fgrid, stats = fun( - new_values, np.array([freq]), fdots=fdot, **fun_kwargs - ) + new_values = new_values - X * np.sin(2 * np.pi * (new_values - T0) / Porb) + fgrid, stats = fun(new_values, np.array([freq]), fdots=fdot, **fun_kwargs) if stats[0] > max_stats: max_stats = stats[0] best_T0 = T0 @@ -349,9 +341,7 @@ def mod(num, n2): @njit() -def shift_and_sum( - repeated_profiles, lshift, qshift, splat_prof, base_shift, quadbaseshift -): +def shift_and_sum(repeated_profiles, lshift, qshift, splat_prof, base_shift, quadbaseshift): nprof = repeated_profiles.shape[0] nbin = splat_prof.size twonbin = nbin * 2 @@ -361,9 +351,7 @@ def shift_and_sum( total_shift = mod(np.rint(total_shift), nbin) total_shift_int = int(total_shift) - splat_prof[:] += repeated_profiles[ - k, nbin - total_shift_int : twonbin - total_shift_int - ] + splat_prof[:] += repeated_profiles[k, nbin - total_shift_int : twonbin - total_shift_int] return splat_prof @@ -563,9 +551,7 @@ def transient_search( times -= meantime maxerr = check_phase_error_after_casting_to_double(np.max(times), f1, fdot) - log.info( - f"Maximum error on the phase expected when casting to double: " f"{maxerr}" - ) + log.info(f"Maximum error on the phase expected when casting to double: " f"{maxerr}") if maxerr > 1 / nbin / 10: warnings.warn( "Casting to double produces non-negligible phase errors. " @@ -689,9 +675,7 @@ def plot_transient_search(results, gif_name=None): f"{gif_name}: Possible candidate at step {i}: {best_f} Hz (~{maxline:.1f} sigma)" ) elif maxline >= 5 and i_f == 0: # pragma: no cover - print( - f"{gif_name}: Candidate at step {i}: {best_f} Hz (~{maxline:.1f} sigma)" - ) + print(f"{gif_name}: Candidate at step {i}: {best_f} Hz (~{maxline:.1f} sigma)") axf.plot(f, mean_line, lw=1, c="k", zorder=10, label="mean", ls="-") @@ -719,9 +703,7 @@ def plot_transient_search(results, gif_name=None): if HAS_IMAGEIO: imageio.v3.imwrite(gif_name, all_images, duration=1000.0) else: - warnings.warn( - "imageio needed to save the transient search results " "into a gif image." - ) + warnings.warn("imageio needed to save the transient search results " "into a gif image.") return all_images @@ -821,9 +803,7 @@ def search_with_qffa_step( # dn = max(1, int(nbin / oversample)) linbinshifts = np.linspace(-nbin * npfact, nbin * npfact, int(oversample * npfact)) if search_fdot: - quabinshifts = np.linspace( - -nbin * npfact, nbin * npfact, int(oversample * npfact) - ) + quabinshifts = np.linspace(-nbin * npfact, nbin * npfact, int(oversample * npfact)) else: quabinshifts = np.array([0]) @@ -905,9 +885,7 @@ def search_with_qffa( maxerr = check_phase_error_after_casting_to_double(np.max(times), f1, fdot) if maxerr > 1 / nbin / 10: - warnings.warn( - f"Maximum error on the phase expected when casting to " f"double: {maxerr}" - ) + warnings.warn(f"Maximum error on the phase expected when casting to " f"double: {maxerr}") warnings.warn( "Casting to double produces non-negligible phase errors. " "Please use shorter light curves.", @@ -1070,11 +1048,7 @@ def folding_search( fdotepsilon = 1e-2 * fdotstep trial_fdots = np.arange(fdotmin, fdotmax + fdotepsilon, fdotstep) if len(trial_fdots) > 1: - log.info( - "Searching {} frequencies and {} fdots".format( - len(trial_freqs), len(trial_fdots) - ) - ) + log.info("Searching {} frequencies and {} fdots".format(len(trial_freqs), len(trial_fdots))) else: log.info("Searching {} frequencies".format(len(trial_freqs))) @@ -1151,14 +1125,11 @@ def print_qffa_results(best_cand_table): if len(newtable[good]) == 0: print("No pulsations found. Best candidate and upper limit:") good = 0 - newtable["Pulsed amplitude (%)"] = [ - f"<{a:g} (90%)" for a in newtable["pulse_amp_ul_0.9"] - ] + newtable["Pulsed amplitude (%)"] = [f"<{a:g} (90%)" for a in newtable["pulse_amp_ul_0.9"]] else: print("Best candidate(s):") newtable["Pulsed amplitude (%)"] = [ - f"{a:g} ± {e:g}" - for (a, e) in zip(newtable["pulse_amp"], newtable["pulse_amp_err"]) + f"{a:g} ± {e:g}" for (a, e) in zip(newtable["pulse_amp"], newtable["pulse_amp_err"]) ] print(newtable["mjd", "f", "fdot", "fddot", "power", "Pulsed amplitude (%)"][good]) @@ -1255,10 +1226,7 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): input_ef_periodogram.M = 1 ntrial = input_ef_periodogram.stat.size - if ( - hasattr(input_ef_periodogram, "oversample") - and input_ef_periodogram.oversample is not None - ): + if hasattr(input_ef_periodogram, "oversample") and input_ef_periodogram.oversample is not None: ntrial /= input_ef_periodogram.oversample ntrial = int(ntrial) if input_ef_periodogram.kind == "Z2n": @@ -1286,10 +1254,7 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): best_cands = find_peaks_in_image(input_ef_periodogram.stat, n=n_cands) fddot = 0 - if ( - hasattr(input_ef_periodogram, "fddots") - and input_ef_periodogram.fddots is not None - ): + if hasattr(input_ef_periodogram, "fddots") and input_ef_periodogram.fddots is not None: fddot = input_ef_periodogram.fddots best_cand_table = Table( @@ -1348,10 +1313,7 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): for i, idx in enumerate(best_cands): f_idx = fdot_idx = fddot_idx = 0 - if ( - len(input_ef_periodogram.stat.shape) > 1 - and input_ef_periodogram.stat.shape[0] > 1 - ): + if len(input_ef_periodogram.stat.shape) > 1 and input_ef_periodogram.stat.shape[0] > 1: f_idx, fdot_idx = idx allfreqs = input_ef_periodogram.freq[f_idx, :] allfdots = input_ef_periodogram.freq[:, fdot_idx] @@ -1362,9 +1324,7 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): input_ef_periodogram.fdots[f_idx, fdot_idx], ) max_stat = input_ef_periodogram.stat[f_idx, fdot_idx] - sig_e1_m, sig_e1 = power_confidence_limits( - max_stat, c=0.68, n=input_ef_periodogram.N - ) + sig_e1_m, sig_e1 = power_confidence_limits(max_stat, c=0.68, n=input_ef_periodogram.N) fmin, fmax, fdotmin, fdotmax = get_xy_boundaries_from_level( input_ef_periodogram.freq, input_ef_periodogram.fdots, @@ -1379,9 +1339,7 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): allstats_f = input_ef_periodogram.stat f = input_ef_periodogram.freq[f_idx] max_stat = input_ef_periodogram.stat[f_idx] - sig_e1_m, sig_e1 = power_confidence_limits( - max_stat, c=0.68, n=input_ef_periodogram.N - ) + sig_e1_m, sig_e1 = power_confidence_limits(max_stat, c=0.68, n=input_ef_periodogram.N) fmin, fmax = get_boundaries_from_level( input_ef_periodogram.freq, input_ef_periodogram.stat, sig_e1_m, f ) @@ -1394,9 +1352,7 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): if input_ef_periodogram.ncounts is None: continue - sig_0, sig_1 = power_confidence_limits( - max_stat, c=0.90, n=input_ef_periodogram.N - ) + sig_0, sig_1 = power_confidence_limits(max_stat, c=0.90, n=input_ef_periodogram.N) amp = amp_err = amp_ul = amp_1 = amp_0 = np.nan if max_stat < detlev: amp_ul = a_from_ssig(sig_1, input_ef_periodogram.ncounts) * 100 @@ -1445,8 +1401,7 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): if fname is not None: Table({"fdot": allfdots, "stat": allstats_fdot}).write( - f'{fname.replace(HEN_FILE_EXTENSION, "")}' - f"_cand_{n_cands - i - 1}_f{f}.dat", + f'{fname.replace(HEN_FILE_EXTENSION, "")}' f"_cand_{n_cands - i - 1}_f{f}.dat", overwrite=True, format="ascii", ) @@ -1584,8 +1539,7 @@ def _common_parser(args=None): "--step", default=None, type=float, - help="Step size of the frequency axis. Defaults to " - "1/oversample/observ.length. ", + help="Step size of the frequency axis. Defaults to " "1/oversample/obs_length. ", ) parser.add_argument( "--oversample", @@ -1593,7 +1547,7 @@ def _common_parser(args=None): type=float, help="Oversampling factor - frequency resolution " "improvement w.r.t. the standard FFT's " - "1/observ.length.", + "1/obs_length.", ) parser.add_argument( "--fast", @@ -1615,8 +1569,7 @@ def _common_parser(args=None): ) parser.add_argument( "--transient", - help="Look for transient emission (produces an animated" - " GIF with the dynamic Z search)", + help="Look for transient emission (produces an animated" " GIF with the dynamic Z search)", default=False, action="store_true", ) @@ -1785,8 +1738,7 @@ def _common_main(args, func): if nbin / n < 8: nbin = n * 8 warnings.warn( - f"The number of bins is too small for Z search." - f"Increasing to {nbin}" + f"The number of bins is too small for Z search." f"Increasing to {nbin}" ) results = search_with_qffa( events.time, @@ -1808,9 +1760,7 @@ def _common_main(args, func): "The Fast Folding Algorithm functionality is experimental. Use" " with care, and feel free to report any issues." ) - results = search_with_ffa( - events.time, args.fmin, args.fmax, nbin=args.nbin, n=n - ) + results = search_with_ffa(events.time, args.fmin, args.fmax, nbin=args.nbin, n=n) ref_time = events.time[0] length = events.time.max() - events.time.min() @@ -1852,9 +1802,7 @@ def _common_main(args, func): pepoch=mjdref + ref_time / 86400, oversample=args.oversample, ) - efperiodogram.upperlim = pf_upper_limit( - np.max(stats), events.time.size, n=args.N - ) + efperiodogram.upperlim = pf_upper_limit(np.max(stats), events.time.size, n=args.N) efperiodogram.ncounts = events.time.size best_peaks = None if args.find_candidates: @@ -1963,9 +1911,7 @@ def main_z2vspf(args=None): type=int, help="Number of trial values for the pulsed fraction", ) - parser.add_argument( - "--outfile", default=None, type=str, help="Output table file name" - ) + parser.add_argument("--outfile", default=None, type=str, help="Output table file name") parser.add_argument( "--show-z-values", nargs="+", @@ -2005,9 +1951,7 @@ def main_z2vspf(args=None): if args.emin is not None or args.emax is not None: events, elabel = filter_energy(events, args.emin, args.emax) - result_table = z2_vs_pf( - events, deadtime=0.0, ntrials=args.ntrial, outfile=outfile, N=args.N - ) + result_table = z2_vs_pf(events, deadtime=0.0, ntrials=args.ntrial, outfile=outfile, N=args.N) if HAS_MPL: fig = plt.figure("Results", figsize=(10, 6)) plt.scatter(result_table["pf"] * 100, result_table["z2"]) @@ -2061,9 +2005,7 @@ def main_accelsearch(args=None): type=float, help="Maximum frequency to search, in Hz", ) - parser.add_argument( - "--nproc", default=1, type=int, help="Number of processors to use" - ) + parser.add_argument("--nproc", default=1, type=int, help="Number of processors to use") parser.add_argument( "--zmax", default=100, @@ -2168,9 +2110,7 @@ def main_accelsearch(args=None): t0 = GTI[0, 0] Nbins = int(np.rint(max_length / dt)) if Nbins > 10**8: - log.info( - f"The number of bins is more than 100 millions: {Nbins}. " "Using memmap." - ) + log.info(f"The number of bins is more than 100 millions: {Nbins}. " "Using memmap.") dt = adjust_dt_for_power_of_two(dt, max_length) diff --git a/hendrics/lcurve.py b/hendrics/lcurve.py index 6c85fd3e..7237f1c7 100644 --- a/hendrics/lcurve.py +++ b/hendrics/lcurve.py @@ -590,7 +590,7 @@ def lcurve_from_fits( except Exception: raise (Exception("TSTART and TSTOP need to be specified")) - # For nulccorr lcs this whould work + # For nulccorr lcs this would work timezero = high_precision_keyword_read(lchdulist[ratehdu].header, "TIMEZERO") # Sometimes timezero is "from tstart", sometimes it's an absolute time. @@ -606,7 +606,7 @@ def lcurve_from_fits( timezero = Time(2440000.5 + timezero, scale="tdb", format="jd") tstart = Time(2440000.5 + tstart, scale="tdb", format="jd") tstop = Time(2440000.5 + tstop, scale="tdb", format="jd") - # if None, use NuSTAR defaulf MJDREF + # if None, use NuSTAR default MJDREF mjdref = assign_value_if_none( mjdref, Time(np.longdouble("55197.00076601852"), scale="tdb", format="mjd"), diff --git a/hendrics/varenergy.py b/hendrics/varenergy.py index 74e22bae..e6d5af06 100644 --- a/hendrics/varenergy.py +++ b/hendrics/varenergy.py @@ -136,7 +136,7 @@ def main(args=None): nargs=2, type=float, default=[0.0, 100], - help="Frequence interval", + help="Frequency interval", ) parser.add_argument( "--energy-values", From 913013c6fddb8041268918d108c931f88c032477 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 12:10:22 +0200 Subject: [PATCH 13/58] Reformat --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index c01f21a8..7940dc39 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,6 @@ from setuptools import setup - # First provide helpful messages if contributors try and run legacy commands # for tests or docs. From e618767466a38d2e43c9e7c84b9f5db17253c592 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 12:11:02 +0200 Subject: [PATCH 14/58] Fix black config --- pyproject.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ceb5666c..431935bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -404,13 +404,14 @@ ignore-words-list = """ hel, lightyear, livetime, + livetimes, lond, nax, nd, ned, nin, numer, - observ.length, + observ, precess, precessed, precesses, @@ -422,3 +423,6 @@ ignore-words-list = """ te, wirth, """ + +[tool.black] +line-length = 100 From a42a79bc857898c340df8a2556eb34c9b5577ddf Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 12:13:07 +0200 Subject: [PATCH 15/58] Run black --- hendrics/base.py | 32 ++---- hendrics/binary.py | 29 ++--- hendrics/create_gti.py | 25 ++--- hendrics/exposure.py | 24 +--- hendrics/fake.py | 31 ++---- hendrics/ffa.py | 12 +- hendrics/fold.py | 62 +++-------- hendrics/fspec.py | 16 +-- hendrics/io.py | 37 ++----- hendrics/lcurve.py | 30 ++--- hendrics/ml_timing.py | 4 +- hendrics/modeling.py | 4 +- hendrics/phaseogram.py | 75 ++++--------- hendrics/phasetag.py | 32 ++---- hendrics/plot.py | 44 ++------ hendrics/power_colors.py | 4 +- hendrics/read_events.py | 41 ++----- hendrics/save_as_xspec.py | 4 +- hendrics/sum_fspec.py | 4 +- hendrics/tests/test_a_complete_run.py | 57 +++------- hendrics/tests/test_base.py | 4 +- hendrics/tests/test_binary.py | 26 ++--- hendrics/tests/test_calibrate.py | 20 +--- hendrics/tests/test_colors.py | 24 +--- hendrics/tests/test_efsearch.py | 16 +-- hendrics/tests/test_fake.py | 51 +++------ hendrics/tests/test_fspec.py | 154 ++++++++------------------ hendrics/tests/test_gti.py | 29 ++--- hendrics/tests/test_io.py | 8 +- hendrics/tests/test_lc.py | 71 ++++-------- hendrics/tests/test_phaseogram.py | 12 +- hendrics/tests/test_phasetag.py | 4 +- hendrics/tests/test_read_events.py | 28 ++--- hendrics/timelags.py | 4 +- hendrics/varenergy.py | 7 +- 35 files changed, 270 insertions(+), 755 deletions(-) diff --git a/hendrics/base.py b/hendrics/base.py index 9a23d4ba..02207289 100644 --- a/hendrics/base.py +++ b/hendrics/base.py @@ -461,14 +461,10 @@ def deorbit_events(events, parameter_file=None, invert=False, ephem=None): """ events = copy.deepcopy(events) if parameter_file is None: - warnings.warn( - "No parameter file specified for deorbit. Returning" " unaltered event list" - ) + warnings.warn("No parameter file specified for deorbit. Returning" " unaltered event list") return events if not os.path.exists(parameter_file): - raise FileNotFoundError( - "Parameter file {} does not exist".format(parameter_file) - ) + raise FileNotFoundError("Parameter file {} does not exist".format(parameter_file)) if events.mjdref < 33282.0: raise ValueError("MJDREF is very low (<01-01-1950), " "this is unsupported.") @@ -664,9 +660,7 @@ def hist1d_numba_seq(a, bins, ranges, use_memmap=False, tmp=None): if bins > 10**7 and use_memmap: if tmp is None: tmp = tempfile.NamedTemporaryFile("w+").name - hist_arr = np.lib.format.open_memmap( - tmp, mode="w+", dtype=a.dtype, shape=(bins,) - ) + hist_arr = np.lib.format.open_memmap(tmp, mode="w+", dtype=a.dtype, shape=(bins,)) else: hist_arr = np.zeros((bins,), dtype=a.dtype) @@ -699,9 +693,7 @@ def hist2d_numba_seq(x, y, bins, ranges): >>> assert np.all(H == Hn) """ H = np.zeros((bins[0], bins[1]), dtype=np.uint64) - return _hist2d_numba_seq( - H, np.array([x, y]), np.asarray(list(bins)), np.asarray(ranges) - ) + return _hist2d_numba_seq(H, np.array([x, y]), np.asarray(list(bins)), np.asarray(ranges)) @njit(nogil=True, parallel=False) @@ -733,9 +725,7 @@ def hist3d_numba_seq(tracks, bins, ranges): """ H = np.zeros((bins[0], bins[1], bins[2]), dtype=np.uint64) - return _hist3d_numba_seq( - H, np.asarray(tracks), np.asarray(list(bins)), np.asarray(ranges) - ) + return _hist3d_numba_seq(H, np.asarray(tracks), np.asarray(list(bins)), np.asarray(ranges)) @njit(nogil=True, parallel=False) @@ -776,9 +766,7 @@ def hist1d_numba_seq_weight(a, weights, bins, ranges, use_memmap=False, tmp=None if bins > 10**7 and use_memmap: if tmp is None: tmp = tempfile.NamedTemporaryFile("w+").name - hist_arr = np.lib.format.open_memmap( - tmp, mode="w+", dtype=a.dtype, shape=(bins,) - ) + hist_arr = np.lib.format.open_memmap(tmp, mode="w+", dtype=a.dtype, shape=(bins,)) else: hist_arr = np.zeros((bins,), dtype=a.dtype) @@ -884,10 +872,7 @@ def _histnd_numba_seq(H, tracks, bins, ranges, slice_int): for t in range(tracks.shape[1]): slicearr = np.array( - [ - (tracks[dim, t] - ranges[dim, 0]) * delta[dim] - for dim in range(tracks.shape[0]) - ] + [(tracks[dim, t] - ranges[dim, 0]) * delta[dim] for dim in range(tracks.shape[0])] ) good = np.all((slicearr < bins) & (slicearr >= 0)) @@ -1160,8 +1145,7 @@ def find_peaks_in_image(image, n=5, rough=False, **kwargs): """ if not HAS_SKIMAGE or rough: best_cands = [ - np.unravel_index(idx, image.shape) - for idx in np.argpartition(image.flatten(), -n)[-n:] + np.unravel_index(idx, image.shape) for idx in np.argpartition(image.flatten(), -n)[-n:] ] __best_stats = [image[bci] for bci in best_cands] best_cands = np.asarray(best_cands)[np.argsort(__best_stats)][::-1] diff --git a/hendrics/binary.py b/hendrics/binary.py index da2e0fa2..dbc8dc83 100644 --- a/hendrics/binary.py +++ b/hendrics/binary.py @@ -35,12 +35,7 @@ def get_header_info(obj): dec = header["DEC_PNT"] a = SkyCoord(ra, dec, unit="degree") - info.raj = ( - (a.ra.to_string("hourangle")) - .replace("s", "") - .replace("h", ":") - .replace("m", ":") - ) + info.raj = (a.ra.to_string("hourangle")).replace("s", "").replace("h", ":").replace("m", ":") info.decj = (a.dec.to_string()).replace("s", "").replace("d", ":").replace("m", ":") if hasattr(obj, "e_interval"): e0, e1 = obj.e_interval @@ -92,9 +87,7 @@ def save_lc_to_binary(lc, filename): return lcinfo -def save_events_to_binary( - events, filename, bin_time, tstart=None, emin=None, emax=None -): +def save_events_to_binary(events, filename, bin_time, tstart=None, emin=None, emax=None): """Save an event list to binary format. Parameters @@ -127,9 +120,7 @@ def save_events_to_binary( if emin is not None and emax is not None: if not hasattr(events, "energy") or events.energy is None: - raise ValueError( - "Energy filtering requested for uncalibrated event " "list" - ) + raise ValueError("Energy filtering requested for uncalibrated event " "list") good = (events.energy >= emin) & (events.energy < emax) events = events.apply_mask(good) @@ -182,8 +173,7 @@ def save_inf(lcinfo, info, filename): with open(filename, "w") as f: print( - " Data file name without suffix " - " = {}".format(filename.replace(".inf", "")), + " Data file name without suffix " " = {}".format(filename.replace(".inf", "")), file=f, ) print( @@ -220,8 +210,7 @@ def save_inf(lcinfo, info, filename): file=f, ) print( - " Width of each time series bin (sec) " - " = {bintime}".format(bintime=lcinfo.dt), + " Width of each time series bin (sec) " " = {bintime}".format(bintime=lcinfo.dt), file=f, ) print(" Any breaks in the data? (1 yes, 0 no) " " = 1", file=f) @@ -229,9 +218,7 @@ def save_inf(lcinfo, info, filename): print( " On/Off bin pair # {ngti:>2} " " = {binstart:<11}, " - "{binstop:<11}".format( - ngti=i + 1, binstart=st, binstop=bin_intervals_stop[i] - ), + "{binstop:<11}".format(ngti=i + 1, binstart=st, binstop=bin_intervals_stop[i]), file=f, ) print(" Type of observation (EM band) " " = X-ray", file=f) @@ -250,9 +237,7 @@ def save_inf(lcinfo, info, filename): ) print(" Any additional notes:", file=f) print( - " T = {length}, Nphot={nphot}".format( - length=lcinfo.tseg, nphot=lcinfo.nphot - ), + " T = {length}, Nphot={nphot}".format(length=lcinfo.tseg, nphot=lcinfo.nphot), file=f, ) diff --git a/hendrics/create_gti.py b/hendrics/create_gti.py index b031f3ec..fd4ff1b0 100644 --- a/hendrics/create_gti.py +++ b/hendrics/create_gti.py @@ -29,9 +29,7 @@ def filter_gti_by_length(gti, minimum_length): return np.array(newgti) -def create_gti( - fname, filter_expr, safe_interval=[0, 0], outfile=None, minimum_length=0 -): +def create_gti(fname, filter_expr, safe_interval=[0, 0], outfile=None, minimum_length=0): """Create a GTI list by using boolean operations on file data. Parameters @@ -73,9 +71,7 @@ def create_gti( if hasattr(data, "internal_array_attrs"): array_attrs = data.internal_array_attrs() mod_array_attrs = [attr.replace("_", "") for attr in array_attrs] - locals().update( - zip(mod_array_attrs, [getattr(data, attr) for attr in array_attrs]) - ) + locals().update(zip(mod_array_attrs, [getattr(data, attr) for attr in array_attrs])) good = eval(filter_expr) @@ -83,9 +79,7 @@ def create_gti( gti = filter_gti_by_length(gti, minimum_length) - outfile = _assign_value_if_none( - outfile, hen_root(fname) + "_gti" + HEN_FILE_EXTENSION - ) + outfile = _assign_value_if_none(outfile, hen_root(fname) + "_gti" + HEN_FILE_EXTENSION) save_data({"gti": gti, "mjdref": mjdref, "__sr__class__type__": "gti"}, outfile) return gti @@ -112,9 +106,7 @@ def apply_gti(fname, gti, outname=None, minimum_length=0): data._mask = None newext = "_gtifilt" + HEN_FILE_EXTENSION - outname = _assign_value_if_none( - outname, fname.replace(HEN_FILE_EXTENSION, "") + newext - ) + outname = _assign_value_if_none(outname, fname.replace(HEN_FILE_EXTENSION, "") + newext) save_data(data, outname) return newgti @@ -126,8 +118,7 @@ def main(args=None): from .base import _add_default_args, check_negative_numbers_in_args description = ( - "Create GTI files from a filter expression, or applies " - "previously created GTIs to a file" + "Create GTI files from a filter expression, or applies " "previously created GTIs to a file" ) parser = argparse.ArgumentParser(description=description) @@ -148,8 +139,7 @@ def main(args=None): "--create-only", default=False, action="store_true", - help="If specified, creates GTIs without applying" - + "them to files (Default: False)", + help="If specified, creates GTIs without applying" + "them to files (Default: False)", ) parser.add_argument( @@ -197,8 +187,7 @@ def main(args=None): filter_expr = args.filter if filter_expr is None and args.apply_gti is None: sys.exit( - "Please specify filter expression (-f option) or input " - "GTI file (-a option)" + "Please specify filter expression (-f option) or input " "GTI file (-a option)" ) for fname in files: diff --git a/hendrics/exposure.py b/hendrics/exposure.py index 014369d5..45f837b9 100644 --- a/hendrics/exposure.py +++ b/hendrics/exposure.py @@ -43,9 +43,7 @@ def get_livetime_per_bin(times, events, priors, dt=None, gti=None): [[time[0] - dt[0]/2, time[-1] + dt[-1]/2]] """ - assert len(events) == len( - priors - ), "`events` and `priors` must be of the same length" + assert len(events) == len(priors), "`events` and `priors` must be of the same length" dt = _assign_value_if_none(dt, np.median(np.diff(times))) @@ -174,15 +172,9 @@ def _plot_dead_time_from_uf(uf_file, outroot="expo"): bins = np.percentile(dead_times, np.linspace(0, 100, 1000)) hist_all, bins_all = histogram(dead_times, bins=bins, density=True) - hist_shield, bins_shield = histogram( - dead_times[shields > 0], bins=bins, density=True - ) - hist_noshield, bins_noshield = histogram( - dead_times[shields == 0], bins=bins, density=True - ) - hist_shld_hi, bins_shld_hi = histogram( - dead_times[shld_hi > 0], bins=bins, density=True - ) + hist_shield, bins_shield = histogram(dead_times[shields > 0], bins=bins, density=True) + hist_noshield, bins_noshield = histogram(dead_times[shields == 0], bins=bins, density=True) + hist_shld_hi, bins_shld_hi = histogram(dead_times[shld_hi > 0], bins=bins, density=True) bin_centers = bins[:-1] + np.diff(bins) / 2 fig = plt.figure("Dead time distribution", figsize=(10, 10)) @@ -299,9 +291,7 @@ def correct_lightcurve(lc_file, uf_file, outname=None, expo_limit=1e-7): outname : str Output file name """ - outname = _assign_value_if_none( - outname, hen_root(lc_file) + "_lccorr" + HEN_FILE_EXTENSION - ) + outname = _assign_value_if_none(outname, hen_root(lc_file) + "_lccorr" + HEN_FILE_EXTENSION) ftype, contents = get_file_type(lc_file) @@ -351,9 +341,7 @@ def main(args=None): default=None, help="Root of output file names", ) - parser.add_argument( - "--plot", help="Plot on window", default=False, action="store_true" - ) + parser.add_argument("--plot", help="Plot on window", default=False, action="store_true") _add_default_args(parser, ["loglevel", "debug"]) args = check_negative_numbers_in_args(args) diff --git a/hendrics/fake.py b/hendrics/fake.py index 8cf27464..7a8057e7 100644 --- a/hendrics/fake.py +++ b/hendrics/fake.py @@ -67,9 +67,7 @@ def _fill_in_default_information(tbheader): False, "TRUE if timestamps corrected by gnd sware", ) - tbheader["COMMENT"] = ( - "MJDREFI+MJDREFF = epoch of Jan 1, 2010, in TT " "time system." - ) + tbheader["COMMENT"] = "MJDREFI+MJDREFF = epoch of Jan 1, 2010, in TT " "time system." tbheader["TIMEUNIT"] = ("s", "unit for time keywords") return tbheader @@ -135,9 +133,7 @@ def generate_fake_fits_observation( inheader = _clean_up_header(inheader) ev_list = event_list.time - gti = assign_value_if_none( - event_list.gti, np.asarray([[ev_list[0], ev_list[-1]]]) - ) + gti = assign_value_if_none(event_list.gti, np.asarray([[ev_list[0], ev_list[-1]]])) mission = assign_value_if_none(mission, event_list.mission) instr = assign_value_if_none(instr, event_list.instr) tstart = assign_value_if_none(tstart, gti[0, 0]) @@ -309,9 +305,7 @@ def _read_light_curve(filename): return lc -def acceptance_rejection( - dt, counts_per_bin, t0=0.0, poissonize_n_events=False, deadtime=0.0 -): +def acceptance_rejection(dt, counts_per_bin, t0=0.0, poissonize_n_events=False, deadtime=0.0): """ Examples -------- @@ -527,8 +521,7 @@ def main_scramble(args=None): from .base import _add_default_args, check_negative_numbers_in_args description = ( - "Scramble the events inside an event list, maintaining the same " - "energies and GTIs" + "Scramble the events inside an event list, maintaining the same " "energies and GTIs" ) parser = argparse.ArgumentParser(description=description) @@ -589,9 +582,7 @@ def main_scramble(args=None): emin, emax = args.energy_interval event_list, elabel = filter_energy(event_list, emin, emax) if elabel != "Energy": - raise ValueError( - "You are filtering by energy but the data are not calibrated" - ) + raise ValueError("You are filtering by energy but the data are not calibrated") new_event_list = scramble( event_list, @@ -617,9 +608,7 @@ def main_scramble(args=None): if args.energy_interval is not None: label += f"_{emin:g}-{emax:g}keV" - outfile = args.fname.replace( - HEN_FILE_EXTENSION, f"{label}" + HEN_FILE_EXTENSION - ) + outfile = args.fname.replace(HEN_FILE_EXTENSION, f"{label}" + HEN_FILE_EXTENSION) save_events(new_event_list, outfile) return outfile @@ -664,9 +653,7 @@ def main(args=None): default="events.evt", help="Output file name", ) - parser.add_argument( - "-i", "--instrument", type=str, default=None, help="Instrument name" - ) + parser.add_argument("-i", "--instrument", type=str, default=None, help="Instrument name") parser.add_argument("-m", "--mission", type=str, default=None, help="Mission name") parser.add_argument( "--tstart", @@ -719,9 +706,7 @@ def main(args=None): tstop = assign_value_if_none(args.tstop, 1024) dt = (tstop - tstart) / 1024 t = np.arange(tstart, tstop + 1, dt) - lc = Lightcurve( - time=t, counts=args.ctrate * dt + np.zeros_like(t), dt=dt - ) + lc = Lightcurve(time=t, counts=args.ctrate * dt + np.zeros_like(t), dt=dt) event_list.simulate_times(lc) nevents = len(event_list.time) event_list.pi = np.zeros(nevents, dtype=int) diff --git a/hendrics/ffa.py b/hendrics/ffa.py index f9445c78..e8a1c232 100644 --- a/hendrics/ffa.py +++ b/hendrics/ffa.py @@ -304,9 +304,7 @@ def ffa_step(array, step, ntables): array_reshaped_dum[prof_n, :] = sum_arrays(array[start, :], rolled[:]) else: - array_reshaped_dum[prof_n, :] = sum_arrays( - array[start, :], array[jumpstart, :] - ) + array_reshaped_dum[prof_n, :] = sum_arrays(array[start, :], array[jumpstart, :]) return array_reshaped_dum @@ -330,9 +328,7 @@ def _ffa(array_reshaped, bin_period, ntables, z_n_n=2): stats = np.zeros(ntables) for i in range(array_reshaped.shape[0]): - stats[i] = _z_n_fast_cached( - array_reshaped[i, :], cached_cos, cached_sin, n=z_n_n - ) + stats[i] = _z_n_fast_cached(array_reshaped[i, :], cached_cos, cached_sin, n=z_n_n) return periods, stats @@ -362,9 +358,7 @@ def _quick_rebin(counts, current_rebin): >>> assert np.allclose(reb, [3, 7, 11, 15, 19]) """ n = int(counts.size // current_rebin) - rebinned_counts = np.sum( - counts[: n * current_rebin].reshape(n, current_rebin), axis=1 - ) + rebinned_counts = np.sum(counts[: n * current_rebin].reshape(n, current_rebin), axis=1) return rebinned_counts diff --git a/hendrics/fold.py b/hendrics/fold.py index 74e3599d..071f9f6c 100644 --- a/hendrics/fold.py +++ b/hendrics/fold.py @@ -35,9 +35,7 @@ def show_progress(a): # import pint HAS_PINT = True except (ImportError, urllib.error.URLError): - warnings.warn( - "PINT is not installed. " "Some pulsar functionality will not be available" - ) + warnings.warn("PINT is not installed. " "Some pulsar functionality will not be available") HAS_PINT = False from .base import deorbit_events @@ -111,9 +109,7 @@ def create_template_from_profile_sins( return template, additional_phase -def create_template_from_profile( - phase, profile, profile_err, imagefile="template.png", norm=1 -): +def create_template_from_profile(phase, profile, profile_err, imagefile="template.png", norm=1): """ Parameters ---------- @@ -422,9 +418,7 @@ def get_TOAs_from_events(events, folding_length, *frequency_derivatives, **kwarg from .ml_timing import ml_pulsefit - pars, errs = ml_pulsefit( - profile, template, calculate_errors=True, fit_base=fit_base - ) + pars, errs = ml_pulsefit(profile, template, calculate_errors=True, fit_base=fit_base) if np.any(np.isnan(pars)) or pars[0] == 0.0 or np.any(np.isnan(errs)): warnings.warn( @@ -452,9 +446,7 @@ def get_TOAs_from_events(events, folding_length, *frequency_derivatives, **kwarg factor = np.std(phs) / np.mean(phs_errs) if phs.size > 15: - log.info( - "Correcting TOA errors for the real scatter. Don't trust them literally" - ) + log.info("Correcting TOA errors for the real scatter. Don't trust them literally") # print(phs, phs_errs, factor) toa_errs = toa_errs * factor @@ -494,9 +486,7 @@ def dbl_cos_fit_func(p, x): base = p[0] startidx = 1 first_harm = p[startidx] * np.cos(2 * np.pi * x + 2 * np.pi * p[startidx + 1]) - second_harm = p[startidx + 2] * np.cos( - 4.0 * np.pi * x + 4 * np.pi * p[startidx + 3] - ) + second_harm = p[startidx + 2] * np.cos(4.0 * np.pi * x + 4 * np.pi * p[startidx + 3]) return base + first_harm + second_harm @@ -533,9 +523,7 @@ def adjust_amp_phase(pars): return pars -def fit_profile_with_sinusoids( - profile, profile_err, debug=False, nperiods=1, baseline=False -): +def fit_profile_with_sinusoids(profile, profile_err, debug=False, nperiods=1, baseline=False): """ Fit a folded profile with the std_fold_fit_func. @@ -594,20 +582,16 @@ def fit_profile_with_sinusoids( if debug: log.debug(guess_pars) plt.plot(x, std_fold_fit_func(guess_pars, x), "r--") - fit_pars, success = optimize.leastsq( - std_residuals, guess_pars[:], args=(x, profile) - ) + fit_pars, success = optimize.leastsq(std_residuals, guess_pars[:], args=(x, profile)) if debug: plt.plot(x, std_fold_fit_func(fit_pars, x), "g--") - fit_pars[startidx : startidx + 2] = adjust_amp_phase( - fit_pars[startidx : startidx + 2] - ) + fit_pars[startidx : startidx + 2] = adjust_amp_phase(fit_pars[startidx : startidx + 2]) fit_pars[startidx + 2 : startidx + 4] = adjust_amp_phase( fit_pars[startidx + 2 : startidx + 4] ) - chisq = np.sum( - (profile - std_fold_fit_func(fit_pars, x)) ** 2 / profile_err**2 - ) / (len(profile) - (startidx + 4)) + chisq = np.sum((profile - std_fold_fit_func(fit_pars, x)) ** 2 / profile_err**2) / ( + len(profile) - (startidx + 4) + ) if debug: plt.plot(x, std_fold_fit_func(fit_pars, x), "b--") if chisq < chisq_save: @@ -696,9 +680,7 @@ def run_folding( smooth_window = np.min([len(profile), 10]) smooth_window = _check_odd(smooth_window) - smoothed_profile = savgol_filter( - profile, window_length=smooth_window, polyorder=3, mode="wrap" - ) + smoothed_profile = savgol_filter(profile, window_length=smooth_window, polyorder=3, mode="wrap") profile = np.concatenate((profile, profile)) smooth = np.concatenate((smoothed_profile, smoothed_profile)) @@ -706,9 +688,7 @@ def run_folding( if plot_energy: histen, _ = np.histogram(energy, bins=biny) - hist2d, _, _ = np.histogram2d( - phases.astype(np.float64), energy, bins=(binx, biny) - ) + hist2d, _, _ = np.histogram2d(phases.astype(np.float64), energy, bins=(binx, biny)) binx = np.concatenate((binx[:-1], binx + 1)) meanbins = (binx[:-1] + binx[1:]) / 2 @@ -749,9 +729,7 @@ def run_folding( color="k", zorder=3, ) - err_low, err_high = poisson_conf_interval( - smooth, interval="frequentist-confidence", sigma=3 - ) + err_low, err_high = poisson_conf_interval(smooth, interval="frequentist-confidence", sigma=3) try: ax0.fill_between( @@ -799,9 +777,7 @@ def run_folding( errs = [] meannrgs = (biny[:-1] + biny[1:]) / 2 for i, prof in enumerate(hist2d_save.T): - smooth = savgol_filter( - prof, window_length=smooth_window, polyorder=3, mode="wrap" - ) + smooth = savgol_filter(prof, window_length=smooth_window, polyorder=3, mode="wrap") mean = np.mean(smooth) shift = 3 * np.sqrt(mean) max = np.max(smooth) @@ -864,12 +840,8 @@ def main_fold(args=None): help="Initial frequency to fold", default=None, ) - parser.add_argument( - "--fdot", type=float, required=False, help="Initial fdot", default=0 - ) - parser.add_argument( - "--fddot", type=float, required=False, help="Initial fddot", default=0 - ) + parser.add_argument("--fdot", type=float, required=False, help="Initial fdot", default=0) + parser.add_argument("--fddot", type=float, required=False, help="Initial fddot", default=0) parser.add_argument( "--tref", type=float, diff --git a/hendrics/fspec.py b/hendrics/fspec.py index 29a51fcf..58c16342 100644 --- a/hendrics/fspec.py +++ b/hendrics/fspec.py @@ -176,9 +176,7 @@ def _provide_periodograms(events, fftlen, dt, norm): for new_ev in _distribute_events(events, fftlen): # Hack: epsilon slightly below zero, to allow for a GTI to be recognized as such new_ev.gti[:, 1] += dt / 10 - pds = AveragedPowerspectrum( - new_ev, dt=dt, segment_size=fftlen, norm=norm, silent=True - ) + pds = AveragedPowerspectrum(new_ev, dt=dt, segment_size=fftlen, norm=norm, silent=True) pds.fftlen = fftlen yield pds @@ -413,9 +411,7 @@ def calc_cpds( "series (e.g. both events or both light curves)" ) - if (emin is not None or emax is not None) and ( - ftype1 != "events" or ftype2 != "events" - ): + if (emin is not None or emax is not None) and (ftype1 != "events" or ftype2 != "events"): warnings.warn("Energy selection only makes sense for event lists") if ftype1 == "events": lc1, _ = filter_energy(lc1, emin, emax) @@ -697,9 +693,7 @@ def dumpdyn_main(args=None): help=("List of files in any valid HENDRICS " "format for PDS or CPDS"), nargs="+", ) - parser.add_argument( - "--noplot", help="plot results", default=False, action="store_true" - ) + parser.add_argument("--noplot", help="plot results", default=False, action="store_true") args = parser.parse_args(args) @@ -758,9 +752,7 @@ def main(args=None): "--norm", type=str, default="leahy", - help="Normalization to use" - + " (Accepted: leahy and rms;" - + ' Default: "leahy")', + help="Normalization to use" + " (Accepted: leahy and rms;" + ' Default: "leahy")', ) parser.add_argument( "--noclobber", diff --git a/hendrics/io.py b/hendrics/io.py index a788b149..204aa2af 100644 --- a/hendrics/io.py +++ b/hendrics/io.py @@ -129,9 +129,7 @@ def find_peaks(self, conflevel=99.0): n_summed_spectra=int(self.M), ) else: - threshold = fold_detection_level( - nbin=int(self.nbin), epsilon=epsilon, ntrial=ntrial - ) + threshold = fold_detection_level(nbin=int(self.nbin), epsilon=epsilon, ntrial=ntrial) if len(self.stat.shape) == 1: best_peaks, best_stat = search_best_peaks(self.freq, self.stat, threshold) @@ -208,10 +206,7 @@ def filter_energy(ev: EventList, emin: float, emax: float) -> Tuple[EventList, s # For some reason the doctest doesn't work if I don't do this instead # of using warnings.warn if elabel == "": - log.error( - "No Energy or PI information available. " - "No energy filter applied to events" - ) + log.error("No Energy or PI information available. " "No energy filter applied to events") return ev, "" if emax is None and emin is None: @@ -505,9 +500,7 @@ def get_file_type(fname, raw_data=False): if "Lightcurve" in ftype_raw: ftype = "lc" fun = load_lcurve - elif ("Powercolor" in ftype_raw) or ( - "StingrayTimeseries" in ftype_raw and "hue" in contents - ): + elif ("Powercolor" in ftype_raw) or ("StingrayTimeseries" in ftype_raw and "hue" in contents): ftype = "powercolor" fun = load_timeseries elif "StingrayTimeseries" in ftype_raw or "Color" in ftype_raw: @@ -714,9 +707,7 @@ def load_folding(fname): # ---- Functions to save PDSs -def save_pds( - cpds, fname, save_all=False, save_dyn=False, no_auxil=False, save_lcs=False -): +def save_pds(cpds, fname, save_all=False, save_dyn=False, no_auxil=False, save_lcs=False): """Save PDS in a file.""" from .base import mkdir_p @@ -763,9 +754,7 @@ def save_pds( lc = getattr(cpds, lcattr) if isinstance(lc, Iterable): if len(lc) > 1: - warnings.warn( - "Saving multiple light curves is not supported. Saving only one" - ) + warnings.warn("Saving multiple light curves is not supported. Saving only one") lc = lc[0] if isinstance(lc, Lightcurve): save_lcurve(lc, lc_name) @@ -826,9 +815,7 @@ def save_pds( def remove_pds(fname): """Remove the pds file and the directory with auxiliary information.""" outdir, _ = splitext_improved(fname) - modelfiles = glob.glob( - os.path.join(outdir, fname.replace(HEN_FILE_EXTENSION, "__mod*__.p")) - ) + modelfiles = glob.glob(os.path.join(outdir, fname.replace(HEN_FILE_EXTENSION, "__mod*__.p"))) for mfile in modelfiles: os.unlink(mfile) if os.path.exists(outdir): @@ -1046,9 +1033,7 @@ def _save_data_nc(struct, fname, kind="data"): # If a (long)double, split it in integer + floating part. # If the number is below zero, also use a logarithm of 10 before # that, so that we don't lose precision - var_I, var_F, var_log10, kind_str = _split_high_precision_number( - k, var, probesize - ) + var_I, var_F, var_log10, kind_str = _split_high_precision_number(k, var, probesize) values.extend([var_I, var_log10, var_F, kind_str]) formats.extend(["i8", "i8", "f8", str]) varnames.extend([k + "_I", k + "_L", k + "_F", k + "_k"]) @@ -1339,9 +1324,7 @@ def save_model(model, fname="model.p", constraints=None): nargs = model.__code__.co_argcount nkwargs = len(model.__defaults__) if not nargs - nkwargs == 1: - raise TypeError( - "Accepted callable models have only one " "non-keyword argument" - ) + raise TypeError("Accepted callable models have only one " "non-keyword argument") modeldata["kind"] = "callable" modeldata["constraints"] = constraints else: @@ -1397,9 +1380,7 @@ def load_model(modelstring): nargs = model.__code__.co_argcount nkwargs = len(model.__defaults__) if not nargs - nkwargs == 1: - raise TypeError( - "Accepted callable models have only one " "non-keyword argument" - ) + raise TypeError("Accepted callable models have only one " "non-keyword argument") return model, "callable", constraints diff --git a/hendrics/lcurve.py b/hendrics/lcurve.py index 7237f1c7..0beb23f3 100644 --- a/hendrics/lcurve.py +++ b/hendrics/lcurve.py @@ -178,9 +178,7 @@ def scrunch_lightcurve_objs(lclist): return lc0 -def scrunch_lightcurves( - lcfilelist, outfile="out_scrlc" + HEN_FILE_EXTENSION, save_joint=False -): +def scrunch_lightcurves(lcfilelist, outfile="out_scrlc" + HEN_FILE_EXTENSION, save_joint=False): """Create a single light curve from input light curves. Light curves are appended when they cover different times, and summed when @@ -224,9 +222,7 @@ def scrunch_lightcurves( return lc0 -def filter_lc_gtis( - lc, safe_interval=None, delete=False, min_length=0, return_borders=False -): +def filter_lc_gtis(lc, safe_interval=None, delete=False, min_length=0, return_borders=False): """Filter a light curve for GTIs. Parameters @@ -378,8 +374,7 @@ def lcurve_from_events( elif e_interval is not None and np.all(np.array(e_interval) > 0): if not hasattr(evdata, "energy") or evdata.energy is None: raise ValueError( - "No energy information is present in the file." - + " Did you run HENcalibrate?" + "No energy information is present in the file." + " Did you run HENcalibrate?" ) es = evdata.energy good = np.logical_and(es > e_interval[0], es <= e_interval[1]) @@ -395,9 +390,7 @@ def lcurve_from_events( ) # Assign default value if None - outfile = assign_value_if_none( - outfile, hen_root(f) + tag + deorbit_tag + weight_on_tag + "_lc" - ) + outfile = assign_value_if_none(outfile, hen_root(f) + tag + deorbit_tag + weight_on_tag + "_lc") # Take out extension from name, if present, then give extension. This # avoids multiple extensions @@ -455,9 +448,7 @@ def lcurve_from_events( lc.instr = instr lc.e_interval = e_interval - lc = filter_lc_gtis( - lc, safe_interval=safe_interval, delete=False, min_length=min_length - ) + lc = filter_lc_gtis(lc, safe_interval=safe_interval, delete=False, min_length=min_length) if len(lc.gti) == 0: warnings.warn("No GTIs above min_length ({0}s) found.".format(min_length)) @@ -631,8 +622,7 @@ def lcurve_from_fits( dt *= 86400 except Exception: warnings.warn( - "Assuming that TIMEDEL is the median difference between the" - " light curve times", + "Assuming that TIMEDEL is the median difference between the" " light curve times", AstropyUserWarning, ) dt = np.median(np.diff(time)) @@ -930,9 +920,7 @@ def main(args=None): default=False, action="store_true", ) - parser.add_argument( - "-d", "--outdir", type=str, default=None, help="Output directory" - ) + parser.add_argument("-d", "--outdir", type=str, default=None, help="Output directory") parser.add_argument( "--noclobber", help="Do not overwrite existing files", @@ -957,9 +945,7 @@ def main(args=None): type=str, help="Use a given attribute of the event list as weights for the light curve", ) - parser = _add_default_args( - parser, ["deorbit", "output", "loglevel", "debug", "nproc"] - ) + parser = _add_default_args(parser, ["deorbit", "output", "loglevel", "debug", "nproc"]) args = check_negative_numbers_in_args(args) args = parser.parse_args(args) diff --git a/hendrics/ml_timing.py b/hendrics/ml_timing.py index 332ffcc2..5c27e022 100644 --- a/hendrics/ml_timing.py +++ b/hendrics/ml_timing.py @@ -192,9 +192,7 @@ def normalized_template(template, tomax=False, subtract_min=True): """ dph = 1 / template.size phase = np.arange(dph / 2, 1, dph) - return normalized_template_func(template, tomax=tomax, subtract_min=subtract_min)( - phase - ) + return normalized_template_func(template, tomax=tomax, subtract_min=subtract_min)(phase) # def estimate_errors(best_fit_templ, ntrial=100, profile_err=None): diff --git a/hendrics/modeling.py b/hendrics/modeling.py index 389a3930..0e1cc991 100644 --- a/hendrics/modeling.py +++ b/hendrics/modeling.py @@ -12,9 +12,7 @@ def main_model(args=None): import argparse from .base import _add_default_args, check_negative_numbers_in_args - description = ( - "Fit frequency spectra (PDS, CPDS, cospectrum) " "with user-defined models" - ) + description = "Fit frequency spectra (PDS, CPDS, cospectrum) " "with user-defined models" parser = argparse.ArgumentParser(description=description) parser.add_argument("files", help="List of light curve files", nargs="+") diff --git a/hendrics/phaseogram.py b/hendrics/phaseogram.py index 7b6a287a..b69ded33 100644 --- a/hendrics/phaseogram.py +++ b/hendrics/phaseogram.py @@ -201,12 +201,8 @@ def __init__( self.phases, self.times = phases, times vmin = None - self.pcolor = ax.pcolormesh( - phases, times, self.phaseogr.T, cmap=self.colormap, vmin=vmin - ) - self.colorbar = plt.colorbar( - self.pcolor, cax=colorbax, orientation="horizontal" - ) + self.pcolor = ax.pcolormesh(phases, times, self.phaseogr.T, cmap=self.colormap, vmin=vmin) + self.colorbar = plt.colorbar(self.pcolor, cax=colorbax, orientation="horizontal") ax.set_xlabel("Phase") def s2d(x): @@ -227,9 +223,7 @@ def d2s(x): self.lines = [] self.line_phases = np.arange(-2, 3, 0.5) for ph0 in self.line_phases: - (newline,) = ax.plot( - np.zeros_like(times) + ph0, times, zorder=10, lw=2, color="w" - ) + (newline,) = ax.plot(np.zeros_like(times) + ph0, times, zorder=10, lw=2, color="w") self.lines.append(newline) ax.set_xlim([0, 2]) @@ -248,29 +242,19 @@ def newax_fn(*args, **kwargs): self._construct_widgets(**kwargs) self.closeax = self.fig.add_axes([0.15, 0.020, 0.15, 0.04]) - self.button_close = Button( - self.closeax, "Quit", color=axcolor, hovercolor="0.8" - ) + self.button_close = Button(self.closeax, "Quit", color=axcolor, hovercolor="0.8") self.recalcax = self.fig.add_axes([0.3, 0.020, 0.15, 0.04]) - self.button_recalc = Button( - self.recalcax, "Recalculate", color=axcolor, hovercolor="0.975" - ) + self.button_recalc = Button(self.recalcax, "Recalculate", color=axcolor, hovercolor="0.975") self.resetax = self.fig.add_axes([0.45, 0.020, 0.15, 0.04]) - self.button_reset = Button( - self.resetax, "Reset", color=axcolor, hovercolor="0.975" - ) + self.button_reset = Button(self.resetax, "Reset", color=axcolor, hovercolor="0.975") self.zoominax = self.fig.add_axes([0.6, 0.020, 0.1, 0.04]) - self.button_zoomin = Button( - self.zoominax, "+Zoom", color=axcolor, hovercolor="0.975" - ) + self.button_zoomin = Button(self.zoominax, "+Zoom", color=axcolor, hovercolor="0.975") self.zoomoutax = self.fig.add_axes([0.7, 0.020, 0.1, 0.04]) - self.button_zoomout = Button( - self.zoomoutax, "-Zoom", color=axcolor, hovercolor="0.975" - ) + self.button_zoomout = Button(self.zoomoutax, "-Zoom", color=axcolor, hovercolor="0.975") self.toaax = self.fig.add_axes([0.8, 0.020, 0.1, 0.04]) self.button_toa = Button(self.toaax, "TOA", color=axcolor, hovercolor="0.975") @@ -286,21 +270,13 @@ def newax_fn(*args, **kwargs): prof = np.sum(np.nan_to_num(self.unnorm_phaseogr), axis=1) nbin = len(prof) phas = np.linspace(0, 2, nbin + 1)[:-1] - (self.profile_fixed,) = self.profax.plot( - phas, prof, drawstyle="steps-post", color="grey" - ) - (self.profile,) = self.profax.plot( - phas, prof, drawstyle="steps-post", color="k" - ) + (self.profile_fixed,) = self.profax.plot(phas, prof, drawstyle="steps-post", color="grey") + (self.profile,) = self.profax.plot(phas, prof, drawstyle="steps-post", color="k") mean = np.mean(prof) - low, high = poisson_conf_interval( - mean, interval="frequentist-confidence", sigma=2 - ) + low, high = poisson_conf_interval(mean, interval="frequentist-confidence", sigma=2) self.profax.fill_between(phas, low, high, alpha=0.5) z2_label = get_H_label(phas, prof) - self.proftext = self.profax.text( - 0.1, 0.8, z2_label, transform=self.profax.transAxes - ) + self.proftext = self.profax.text(0.1, 0.8, z2_label, transform=self.profax.transAxes) if not test and not plot_only: plt.show() if plot_only: @@ -320,8 +296,7 @@ def recalculate(self, event): # pragma: no cover def toa(self, event): # pragma: no cover warnings.warn( - "This function was not implemented for this Phaseogram. " - "Try the basic one.", + "This function was not implemented for this Phaseogram. " "Try the basic one.", AstropyUserWarning, ) @@ -484,12 +459,8 @@ def get_timing_model_string(self): tm_string += "PEPOCH {}\n".format(self.pepoch / 86400 + self.mjdref) tm_string += "PSRJ {}\n".format(self.object) if self.position is not None: - tm_string += "RAJ {}\n".format( - self.position.ra.to_string("hour", sep=":") - ) - tm_string += "DECJ {}\n".format( - self.position.dec.to_string(sep=":") - ) + tm_string += "RAJ {}\n".format(self.position.ra.to_string("hour", sep=":")) + tm_string += "DECJ {}\n".format(self.position.dec.to_string(sep=":")) tm_string += "F0 {}\n".format(self.freq) tm_string += "F1 {}\n".format(self.fdot) @@ -800,9 +771,7 @@ def _line_delay_fun(self, times): orbital_period, asini, t0 = self._read_sliders() new_values = asini * np.sin(2 * np.pi * (times - t0) / orbital_period) - old_values = self.asini * np.sin( - 2 * np.pi * (times - self.t0) / (self.orbital_period) - ) + old_values = self.asini * np.sin(2 * np.pi * (times - self.t0) / (self.orbital_period)) return (new_values - old_values) * self.freq def _delay_fun(self, times): @@ -995,12 +964,8 @@ def main_phaseogram(args=None): help="Initial frequency to fold", default=None, ) - parser.add_argument( - "--fdot", type=float, required=False, help="Initial fdot", default=0 - ) - parser.add_argument( - "--fddot", type=float, required=False, help="Initial fddot", default=0 - ) + parser.add_argument("--fdot", type=float, required=False, help="Initial fdot", default=0) + parser.add_argument("--fddot", type=float, required=False, help="Initial fddot", default=0) parser.add_argument( "--periodogram", type=str, @@ -1081,9 +1046,7 @@ def main_phaseogram(args=None): with log.log_to_file("HENphaseogram.log"): if args.periodogram is None and args.freq is None: - raise ValueError( - "One of -f or --periodogram arguments MUST be " "specified" - ) + raise ValueError("One of -f or --periodogram arguments MUST be " "specified") elif args.periodogram is not None: periodogram = load_folding(args.periodogram) frequency = float(periodogram.peaks[0]) diff --git a/hendrics/phasetag.py b/hendrics/phasetag.py index 18e24c5c..d94bffdd 100644 --- a/hendrics/phasetag.py +++ b/hendrics/phasetag.py @@ -101,9 +101,7 @@ def phase_tag( f = frequency_derivatives[0] phase = pulse_phase(times, *frequency_derivatives, to_1=False) - gti_phases = pulse_phase( - (gti_mjd - pepoch) * 86400, *frequency_derivatives, to_1=False - ) + gti_phases = pulse_phase((gti_mjd - pepoch) * 86400, *frequency_derivatives, to_1=False) # ------- now apply period derivatives ------ @@ -118,15 +116,11 @@ def phase_tag( phase_to1 = phase - np.floor(phase) raw_profile, bins = np.histogram(phase_to1, bins=np.linspace(0, 1, nbin + 1)) - exposure = phase_exposure( - gti_phases[0, 0], gti_phases[-1, 1], 1, nbin=nbin, gti=gti_phases - ) + exposure = phase_exposure(gti_phases[0, 0], gti_phases[-1, 1], 1, nbin=nbin, gti=gti_phases) profile = raw_profile / exposure profile_err = np.sqrt(raw_profile) / exposure - sinpars, bu, bu = fit_profile( - profile, profile_err, nperiods=2, baseline=True, debug=test - ) + sinpars, bu, bu = fit_profile(profile, profile_err, nperiods=2, baseline=True, debug=test) fine_phases = np.linspace(0, 2, 1000 * 2) fitted_profile = std_fold_fit_func(sinpars, fine_phases) maxp = np.argmax(fitted_profile) @@ -143,9 +137,7 @@ def phase_tag( raw_profile, bins = np.histogram(phase_to1, bins=np.linspace(0, 1, nbin + 1)) - exposure = phase_exposure( - gti_phases[0, 0], gti_phases[-1, 1], 1, nbin=nbin, gti=gti_phases - ) + exposure = phase_exposure(gti_phases[0, 0], gti_phases[-1, 1], 1, nbin=nbin, gti=gti_phases) if np.any(np.logical_or(exposure != exposure, exposure == 0)): warnings.warn( "Exposure has NaNs or zeros. Profile is not normalized", @@ -197,7 +189,7 @@ def phase_tag_fits( gti_file=None, hduname="EVENTS", column="TIME", - **kwargs + **kwargs, ): """Phase-tag events in a FITS file with a given ephemeris. @@ -245,11 +237,7 @@ def phase_tag_fits( mjdref = ref_mjd(filename) results = phase_tag( - evreturns.ev_list, - parameter_info, - gti=evreturns.gti_list, - mjdref=mjdref, - **kwargs + evreturns.ev_list, parameter_info, gti=evreturns.gti_list, mjdref=mjdref, **kwargs ) if results.figure is not None: results.figure.savefig(hen_root(filename) + ".pdf") @@ -289,9 +277,7 @@ def phase_tag_fits( if create: # then, create new column with orbital demodulation - newcol = pf.Column( - name="Orbit_bary", format="1D", unit="s", array=results.ev_list - ) + newcol = pf.Column(name="Orbit_bary", format="1D", unit="s", array=results.ev_list) # append it to new table newlist.append(newcol) @@ -318,9 +304,7 @@ def phase_tag_fits( newrec = pf.FITS_rec.from_columns(coldefs) # and new hdu - newtbhdu = pf.BinTableHDU( - data=newrec, header=tbhdu.header.copy(), name=hduname, uint=False - ) + newtbhdu = pf.BinTableHDU(data=newrec, header=tbhdu.header.copy(), name=hduname, uint=False) # Copy primary HDU from old file prihdu = hdulist[0].copy() diff --git a/hendrics/plot.py b/hendrics/plot.py index c8c86042..5ec51117 100644 --- a/hendrics/plot.py +++ b/hendrics/plot.py @@ -204,15 +204,9 @@ def plot_powercolors(fnames): ts = load_data(fnames) - plot_power_colors( - ts["pc1"], ts["pc1_err"], ts["pc2"], ts["pc2_err"], plot_spans=True - ) - plot_hues( - ts["rms"], ts["rms_err"], ts["pc1"], ts["pc2"], polar=True, plot_spans=True - ) - plot_hues( - ts["rms"], ts["rms_err"], ts["pc1"], ts["pc2"], polar=False, plot_spans=True - ) + plot_power_colors(ts["pc1"], ts["pc1_err"], ts["pc2"], ts["pc2_err"], plot_spans=True) + plot_hues(ts["rms"], ts["rms_err"], ts["pc1"], ts["pc2"], polar=True, plot_spans=True) + plot_hues(ts["rms"], ts["rms_err"], ts["pc1"], ts["pc2"], polar=False, plot_spans=True) return ts @@ -494,9 +488,7 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No mean = np.mean(profile) - low, high = poisson_conf_interval( - mean, interval="frequentist-confidence", sigma=1 - ) + low, high = poisson_conf_interval(mean, interval="frequentist-confidence", sigma=1) ax.axhline(mean) ax.fill_between( @@ -506,9 +498,7 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No label=r"1-$\sigma c.l.$", alpha=0.5, ) - low, high = poisson_conf_interval( - mean, interval="frequentist-confidence", sigma=3 - ) + low, high = poisson_conf_interval(mean, interval="frequentist-confidence", sigma=3) ax.fill_between( [0, 2], [low, low], @@ -624,9 +614,7 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No cbar = plt.colorbar(pcol, cax=axcolor, ticks=colorticks) if len(cs.allsegs[0]) > 1: - warnings.warn( - "More than one contour found. " "Frequency estimates might be wrong" - ) + warnings.warn("More than one contour found. " "Frequency estimates might be wrong") else: for ax in (axffdot, axf): ax.axvline(cs.allsegs[0][0][:, 0].min(), label=f"90% conf. lim.") @@ -684,11 +672,7 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No axf.set_ylabel(ef.kind + " stat") axf.legend(loc=4) - if ( - hasattr(ef, "best_fits") - and ef.best_fits is not None - and not len(ef.stat.shape) > 1 - ): + if hasattr(ef, "best_fits") and ef.best_fits is not None and not len(ef.stat.shape) > 1: for f in ef.best_fits: xs = np.linspace(np.min(ef.freq), np.max(ef.freq), len(ef.freq) * 2) plt.plot(xs, f(xs)) @@ -701,11 +685,7 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No out = [ef.freq.flatten(), fdots.flatten(), ef.stat.flatten()] out_err = [None, None, None] - if ( - hasattr(ef, "best_fits") - and ef.best_fits is not None - and not len(ef.stat.shape) > 1 - ): + if hasattr(ef, "best_fits") and ef.best_fits is not None and not len(ef.stat.shape) > 1: for f in ef.best_fits: out.append(f(ef.freq.flatten())) out_err.append(None) @@ -892,12 +872,8 @@ def main(args=None): default=None, action="store_true", ) - parser.add_argument( - "--xlin", help="Use linear X axis", default=False, action="store_true" - ) - parser.add_argument( - "--ylin", help="Use linear Y axis", default=False, action="store_true" - ) + parser.add_argument("--xlin", help="Use linear X axis", default=False, action="store_true") + parser.add_argument("--ylin", help="Use linear Y axis", default=False, action="store_true") parser.add_argument( "--white-sub", help="Subtract Poisson noise (only applies to PDS)", diff --git a/hendrics/power_colors.py b/hendrics/power_colors.py index 8d13d9eb..3be9880d 100644 --- a/hendrics/power_colors.py +++ b/hendrics/power_colors.py @@ -92,9 +92,7 @@ def treat_power_colors( ) good = (scolor.pc1 > 0) & (scolor.pc2 > 0) if np.any(~good): - warnings.warn( - "Some (non-log) power colors are negative. Neglecting them", UserWarning - ) + warnings.warn("Some (non-log) power colors are negative. Neglecting them", UserWarning) scolor = scolor.apply_mask(good) if outfile is None: diff --git a/hendrics/read_events.py b/hendrics/read_events.py index 8a4db761..e877001d 100644 --- a/hendrics/read_events.py +++ b/hendrics/read_events.py @@ -88,9 +88,7 @@ def treat_event_file( good = lc.counts > 0 new_bad = (~good) & good_gti if np.any(new_bad): - warnings.warn( - f"Found zero counts in the light curve at times{lc.time[new_bad]}" - ) + warnings.warn(f"Found zero counts in the light curve at times{lc.time[new_bad]}") gti = create_gti_from_condition( lc.time, (good_gti & good), safe_interval=bin_time_for_occultations ) @@ -102,9 +100,7 @@ def treat_event_file( detector_id = events.detector_id if randomize_by is not None: - events.time += np.random.uniform( - -randomize_by / 2, randomize_by / 2, events.time.size - ) + events.time += np.random.uniform(-randomize_by / 2, randomize_by / 2, events.time.size) if fill_small_gaps is not None: events = events.fill_bad_time_intervals(fill_small_gaps) @@ -148,15 +144,13 @@ def treat_event_file( for ig, g in enumerate(gti_chunks): outfile_local = ( - "{0}_{1}{2:03d}_ev".format(outroot_local, label, ig) - + HEN_FILE_EXTENSION + "{0}_{1}{2:03d}_ev".format(outroot_local, label, ig) + HEN_FILE_EXTENSION ) good_gti = cross_two_gtis([g], gti) if noclobber and os.path.exists(outfile_local): warnings.warn( - "{0} exists, ".format(outfile_local) - + "and noclobber option used. Skipping" + "{0} exists, ".format(outfile_local) + "and noclobber option used. Skipping" ) return good = np.logical_and(events.time >= g[0], events.time < g[1]) @@ -278,9 +272,7 @@ def join_eventlists(event_file1, event_file2, new_event_file=None, ignore_instr= Output event file """ if new_event_file is None: - new_event_file = ( - common_name(event_file1, event_file2) + "_ev" + HEN_FILE_EXTENSION - ) + new_event_file = common_name(event_file1, event_file2) + "_ev" + HEN_FILE_EXTENSION events1 = load_events(event_file1) events2 = load_events(event_file2) @@ -353,11 +345,7 @@ def join_many_eventlists(eventfiles, new_event_file=None, ignore_instr=False): if not np.isclose(events.mjdref, first_events.mjdref): warnings.warn(f"{event_file} has a different MJDREF") continue - if ( - hasattr(events, "instr") - and not events.instr == first_events.instr - and not ignore_instr - ): + if hasattr(events, "instr") and not events.instr == first_events.instr and not ignore_instr: warnings.warn(f"{event_file} is from a different instrument") continue elif ignore_instr: @@ -466,14 +454,11 @@ def main_join(args=None): import argparse description = ( - "Read a cleaned event files and saves the relevant " - "information in a standard format" + "Read a cleaned event files and saves the relevant " "information in a standard format" ) parser = argparse.ArgumentParser(description=description) parser.add_argument("files", help="Files to join", type=str, nargs="+") - parser.add_argument( - "-o", "--output", type=str, help="Name of output file", default=None - ) + parser.add_argument("-o", "--output", type=str, help="Name of output file", default=None) parser.add_argument( "--ignore-instr", help="Ignore instrument names in channels", @@ -517,8 +502,7 @@ def main_splitevents(args=None): parser.add_argument( "--overlap", type=float, - help="Overlap factor. 0 for no overlap, 0.5 for " - "half-interval overlap, and so on.", + help="Overlap factor. 0 for no overlap, 0.5 for " "half-interval overlap, and so on.", default=None, ) parser.add_argument( @@ -532,9 +516,7 @@ def main_splitevents(args=None): if args.split_at_mjd is not None: return split_eventlist_at_mjd(args.fname, mjd=args.split_at_mjd) - return split_eventlist( - args.fname, max_length=args.length_split, overlap=args.overlap - ) + return split_eventlist(args.fname, max_length=args.length_split, overlap=args.overlap) def main(args=None): @@ -544,8 +526,7 @@ def main(args=None): from .base import _add_default_args, check_negative_numbers_in_args description = ( - "Read a cleaned event files and saves the relevant " - "information in a standard format" + "Read a cleaned event files and saves the relevant " "information in a standard format" ) parser = argparse.ArgumentParser(description=description) parser.add_argument("files", help="List of files", nargs="+") diff --git a/hendrics/save_as_xspec.py b/hendrics/save_as_xspec.py index 7202d0e6..eef9cd72 100644 --- a/hendrics/save_as_xspec.py +++ b/hendrics/save_as_xspec.py @@ -50,9 +50,7 @@ def save_as_xspec(fname, direct_save=False, save_lags=True): np.transpose([flo, fhi, lags * contents.df, lags_err * contents.df]), ) if direct_save: - sp.check_call( - "flx2xsp {0} {1}.pha {1}.rsp".format(outname_lags, outroot_lags).split() - ) + sp.check_call("flx2xsp {0} {1}.pha {1}.rsp".format(outname_lags, outroot_lags).split()) def main(args=None): diff --git a/hendrics/sum_fspec.py b/hendrics/sum_fspec.py index 19ec8ba7..d4325236 100644 --- a/hendrics/sum_fspec.py +++ b/hendrics/sum_fspec.py @@ -46,9 +46,7 @@ def main(args=None): "--outname", type=str, default=None, - help="Output file name for summed (C)PDS. Default:" - + " tot_(c)pds" - + HEN_FILE_EXTENSION, + help="Output file name for summed (C)PDS. Default:" + " tot_(c)pds" + HEN_FILE_EXTENSION, ) args = parser.parse_args(args) diff --git a/hendrics/tests/test_a_complete_run.py b/hendrics/tests/test_a_complete_run.py index bd480ff2..1535faae 100644 --- a/hendrics/tests/test_a_complete_run.py +++ b/hendrics/tests/test_a_complete_run.py @@ -66,17 +66,11 @@ class TestFullRun(object): def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) - cls.ev_fileB = os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, @@ -92,12 +86,8 @@ def setup_class(cls): ) hen.read_events.main(command.split()) command = "{} {} -r {}".format( - os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ), - os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ), + os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), + os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "test.rmf"), ) hen.calibrate.main(command.split()) @@ -107,31 +97,23 @@ def setup_class(cls): cls.lcB = os.path.join( os.path.join(cls.datadir, "monol_testB_E3-50_lc" + HEN_FILE_EXTENSION) ) - command = ( - "{} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " "-o {}" - ).format(cls.ev_fileAcal, cls.lcA) + command = ("{} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " "-o {}").format( + cls.ev_fileAcal, cls.lcA + ) hen.lcurve.main(command.split()) - command = ( - "{} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " "-o {}" - ).format(cls.ev_fileBcal, cls.lcB) + command = ("{} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " "-o {}").format( + cls.ev_fileBcal, cls.lcB + ) hen.lcurve.main(command.split()) - cls.pdsA = os.path.join( - cls.datadir, "monol_testA_E3-50_pds" + HEN_FILE_EXTENSION - ) - cls.pdsB = os.path.join( - cls.datadir, "monol_testB_E3-50_pds" + HEN_FILE_EXTENSION - ) - cls.cpds = os.path.join( - cls.datadir, "monol_test_E3-50_cpds" + HEN_FILE_EXTENSION - ) + cls.pdsA = os.path.join(cls.datadir, "monol_testA_E3-50_pds" + HEN_FILE_EXTENSION) + cls.pdsB = os.path.join(cls.datadir, "monol_testB_E3-50_pds" + HEN_FILE_EXTENSION) + cls.cpds = os.path.join(cls.datadir, "monol_test_E3-50_cpds" + HEN_FILE_EXTENSION) command = "{} {} -f 128 -k PDS --save-all --norm leahy".format(cls.lcA, cls.lcB) hen.fspec.main(command.split()) - command = "{} {} -f 128 -k CPDS --save-all --norm leahy".format( - cls.lcA, cls.lcB - ) + command = "{} {} -f 128 -k CPDS --save-all --norm leahy".format(cls.lcA, cls.lcB) hen.fspec.main(command.split()) assert os.path.exists(cls.cpds) assert os.path.exists(cls.pdsA) @@ -229,9 +211,7 @@ def test_power_colors(self): def test_power_colors_2files(self): """Test light curve using PI filtering.""" # calculate colors - command = ( - f"--cross {self.ev_fileAcal} {self.ev_fileBcal} -s 16 -b -6 -f 1 2 4 8 16 " - ) + command = f"--cross {self.ev_fileAcal} {self.ev_fileBcal} -s 16 -b -6 -f 1 2 4 8 16 " with pytest.warns( UserWarning, match="(Some .non-log.)|(All power spectral)|(Poisson-subtracted)|(cast to real)", @@ -291,10 +271,7 @@ def test_plot_hid(self): ) hen.lcurve.main(command.split()) - lname = ( - os.path.join(self.datadir, "monol_testA_nustar_fpma_E3-10_lc") - + HEN_FILE_EXTENSION - ) + lname = os.path.join(self.datadir, "monol_testA_nustar_fpma_E3-10_lc") + HEN_FILE_EXTENSION os.path.exists(lname) cname = ( os.path.join(self.datadir, "monol_testA_nustar_fpma_E_10-5_over_5-3") diff --git a/hendrics/tests/test_base.py b/hendrics/tests/test_base.py index 4265a562..90c6bcc9 100644 --- a/hendrics/tests/test_base.py +++ b/hendrics/tests/test_base.py @@ -59,9 +59,7 @@ def test_deorbit_badpar(): def test_deorbit_non_existing_par(): ev = np.asarray(1) - with pytest.raises( - FileNotFoundError, match="Parameter file warjladsfjqpeifjsdk.par" - ): + with pytest.raises(FileNotFoundError, match="Parameter file warjladsfjqpeifjsdk.par"): deorbit_events(ev, "warjladsfjqpeifjsdk.par") diff --git a/hendrics/tests/test_binary.py b/hendrics/tests/test_binary.py index 0b3f3f69..5f02f0f2 100644 --- a/hendrics/tests/test_binary.py +++ b/hendrics/tests/test_binary.py @@ -34,39 +34,29 @@ class TestBinary(object): def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) - cls.ev_fileB = os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, ) cls.par = _dummy_par("bubububu.par") - command = "{0} --discard-calibration".format( - os.path.join(cls.datadir, "monol_testA.evt") - ) + command = "{0} --discard-calibration".format(os.path.join(cls.datadir, "monol_testA.evt")) hen.read_events.main(command.split()) command = "{} -r {}".format( - os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ), + os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "test.rmf"), ) hen.calibrate.main(command.split()) cls.lcA = os.path.join( os.path.join(cls.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) ) - command = ( - "{} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " "-o {}" - ).format(cls.ev_fileAcal, cls.lcA) + command = ("{} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " "-o {}").format( + cls.ev_fileAcal, cls.lcA + ) hen.lcurve.main(command.split()) def test_save_binary_events(self): diff --git a/hendrics/tests/test_calibrate.py b/hendrics/tests/test_calibrate.py index 94b64165..fdd69d3d 100644 --- a/hendrics/tests/test_calibrate.py +++ b/hendrics/tests/test_calibrate.py @@ -28,17 +28,11 @@ class TestCalibrate(object): def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) - cls.ev_fileB = os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, @@ -55,12 +49,8 @@ def setup_class(cls): ) hen.read_events.main(command.split()) command = "{} {} -r {} --nproc 2".format( - os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ), - os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ), + os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), + os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION), cls.rmf, ) hen.calibrate.main(command.split()) diff --git a/hendrics/tests/test_colors.py b/hendrics/tests/test_colors.py index 7d519766..902818e7 100644 --- a/hendrics/tests/test_colors.py +++ b/hendrics/tests/test_colors.py @@ -63,17 +63,11 @@ class TestFullRun(object): def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) - cls.ev_fileB = os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, @@ -90,12 +84,8 @@ def setup_class(cls): hen.read_events.main(command.split()) command = "{} {} -r {}".format( - os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ), - os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ), + os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), + os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "test.rmf"), ) hen.calibrate.main(command.split()) @@ -150,9 +140,7 @@ def test_plot_color(self): def test_plot_hid(self): """Test plotting with linear axes.""" # also produce a light curve with the same binning - command = ("{0} -b 100 --energy-interval {1} {2}").format( - self.ev_fileAcal, 3, 10 - ) + command = ("{0} -b 100 --energy-interval {1} {2}").format(self.ev_fileAcal, 3, 10) hen.lcurve.main(command.split()) lname = self.lc3_10 diff --git a/hendrics/tests/test_efsearch.py b/hendrics/tests/test_efsearch.py index 8ce0ef69..6484c96d 100644 --- a/hendrics/tests/test_efsearch.py +++ b/hendrics/tests/test_efsearch.py @@ -67,9 +67,7 @@ def setup_class(cls): cls.dum_scramble = "events_scramble" + HEN_FILE_EXTENSION save_events(events, cls.dum) events_scramble = copy.deepcopy(events) - events_scramble.time = np.sort( - np.random.uniform(cls.tstart, cls.tend, events.time.size) - ) + events_scramble.time = np.sort(np.random.uniform(cls.tstart, cls.tend, events.time.size)) save_events(events_scramble, cls.dum_scramble) cls.par = "bububububu.par" _dummy_par(cls.par) @@ -123,9 +121,7 @@ def test_get_TOAs_template(self): def test_fit_profile_with_sinusoids(self): nbin = 32 phases = np.arange(0, 1, 1 / nbin) - prof_smooth = np.cos(2 * np.pi * phases) + 0.5 * np.cos( - 4 * np.pi * (phases + 0.5) - ) + prof_smooth = np.cos(2 * np.pi * phases) + 0.5 * np.cos(4 * np.pi * (phases + 0.5)) prof_smooth = (prof_smooth + 5) * 64 prof = np.random.poisson(prof_smooth) baseline = np.mean(prof) @@ -575,9 +571,7 @@ def test_zsearch_fdots_ffa(self): def test_fold_fast_fails(self): evfile = self.dum - with pytest.raises( - ValueError, match="The fast option is only available for z " - ): + with pytest.raises(ValueError, match="The fast option is only available for z "): main_efsearch([evfile, "-f", "9.85", "-F", "9.95", "-n", "64", "--fast"]) def test_zsearch_fdots_fast_transient(self): @@ -718,9 +712,7 @@ def test_accelsearch(self): def test_accelsearch_nodetections(self): evfile = self.dum_scramble with pytest.warns(UserWarning, match="The accelsearch functionality"): - outfile = main_accelsearch( - [evfile, "--fmin", "1", "--fmax", "1.1", "--zmax", "1"] - ) + outfile = main_accelsearch([evfile, "--fmin", "1", "--fmax", "1.1", "--zmax", "1"]) assert os.path.exists(outfile) os.unlink(outfile) diff --git a/hendrics/tests/test_fake.py b/hendrics/tests/test_fake.py index ec7f1406..c31287f5 100644 --- a/hendrics/tests/test_fake.py +++ b/hendrics/tests/test_fake.py @@ -34,9 +34,7 @@ def test_filter_for_deadtime_nonpar(): events = np.array([1, 1.05, 1.07, 1.08, 1.1, 2, 2.2, 3, 3.1, 3.2]) filt_events = hen.fake.filter_for_deadtime(events, 0.11) expected = np.array([1, 2, 2.2, 3, 3.2]) - assert np.all(filt_events == expected), "Wrong: {} vs {}".format( - filt_events, expected - ) + assert np.all(filt_events == expected), "Wrong: {} vs {}".format(filt_events, expected) def test_filter_for_deadtime_nonpar_bkg(): @@ -48,20 +46,15 @@ def test_filter_for_deadtime_nonpar_bkg(): ) expected_ev = np.array([2, 2.2, 3, 3.2]) expected_bk = np.array([1]) - assert np.all(filt_events == expected_ev), "Wrong: {} vs {}".format( - filt_events, expected_ev - ) - assert np.all(info.bkg == expected_bk), "Wrong: {} vs {}".format( - info.bkg, expected_bk - ) + assert np.all(filt_events == expected_ev), "Wrong: {} vs {}".format(filt_events, expected_ev) + assert np.all(info.bkg == expected_bk), "Wrong: {} vs {}".format(info.bkg, expected_bk) def test_filter_for_deadtime_par(): """Test dead time filter, paralyzable case.""" events = np.array([1, 1.1, 2, 2.2, 3, 3.1, 3.2]) assert np.all( - hen.fake.filter_for_deadtime(events, 0.11, paralyzable=True) - == np.array([1, 2, 2.2, 3]) + hen.fake.filter_for_deadtime(events, 0.11, paralyzable=True) == np.array([1, 2, 2.2, 3]) ) @@ -78,12 +71,8 @@ def test_filter_for_deadtime_par_bkg(): ) expected_ev = np.array([2, 2.2, 3]) expected_bk = np.array([1]) - assert np.all(filt_events == expected_ev), "Wrong: {} vs {}".format( - filt_events, expected_ev - ) - assert np.all(info.bkg == expected_bk), "Wrong: {} vs {}".format( - info.bkg, expected_bk - ) + assert np.all(filt_events == expected_ev), "Wrong: {} vs {}".format(filt_events, expected_ev) + assert np.all(info.bkg == expected_bk), "Wrong: {} vs {}".format(info.bkg, expected_bk) def test_filter_for_deadtime_par_bkg_obj(): @@ -108,18 +97,10 @@ def test_filter_for_deadtime_par_bkg_obj(): filt_pis = filt_events.pi filt_nrgs = filt_events.energy - assert np.all(filt_times == expected_ev), "Wrong: {} vs {}".format( - filt_events, expected_ev - ) - assert np.all(filt_pis == expected_pi), "Wrong: {} vs {}".format( - filt_events, expected_ev - ) - assert np.all(filt_nrgs == expected_nrg), "Wrong: {} vs {}".format( - filt_events, expected_ev - ) - assert np.all(info.bkg == expected_bk), "Wrong: {} vs {}".format( - info.bkg, expected_bk - ) + assert np.all(filt_times == expected_ev), "Wrong: {} vs {}".format(filt_events, expected_ev) + assert np.all(filt_pis == expected_pi), "Wrong: {} vs {}".format(filt_events, expected_ev) + assert np.all(filt_nrgs == expected_nrg), "Wrong: {} vs {}".format(filt_events, expected_ev) + assert np.all(info.bkg == expected_bk), "Wrong: {} vs {}".format(info.bkg, expected_bk) def test_deadtime_mask_par(): @@ -177,9 +158,7 @@ def setup_class(cls): hen.read_events.main(command.split()) cls.first_event_file_cal = "calibrated" + HEN_FILE_EXTENSION - hen.calibrate.calibrate( - cls.first_event_file, cls.first_event_file_cal, rough=True - ) + hen.calibrate.calibrate(cls.first_event_file, cls.first_event_file_cal, rough=True) cls.xmm_fits_file = os.path.join(cls.datadir, "monol_test_fake_lc_xmm.evt") # Note that I don't specify the instrument. This is because @@ -319,9 +298,7 @@ def test_scramble_events(self): # Put exactly one photon inside a very short GTI times[0] = 0.5 times = np.sort(times) - event_list = EventList( - times, gti=np.array([[0, 0.9], [111, 123.2], [125.123, 1000]]) - ) + event_list = EventList(times, gti=np.array([[0, 0.9], [111, 123.2], [125.123, 1000]])) new_event_list = scramble(event_list, "smooth") assert new_event_list.time.size == times.size @@ -334,9 +311,7 @@ def test_scramble_events(self): def test_calibrate_xmm(self): """Test event file calibration.""" xmm_file = self.xmm_ev_file - command = "{0} -r {1} --nproc 2".format( - xmm_file, os.path.join(self.datadir, "test.rmf") - ) + command = "{0} -r {1} --nproc 2".format(xmm_file, os.path.join(self.datadir, "test.rmf")) with pytest.raises(RuntimeError): hen.calibrate.main(command.split()) diff --git a/hendrics/tests/test_fspec.py b/hendrics/tests/test_fspec.py index 8850b6fc..84dd90a1 100644 --- a/hendrics/tests/test_fspec.py +++ b/hendrics/tests/test_fspec.py @@ -62,9 +62,7 @@ def test_cpds_fails_noclobber_exists(): def test_distributed_pds(): - events = EventList( - np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]]) - ) + events = EventList(np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]])) if hasattr(stingray.AveragedPowerspectrum, "from_events"): single_periodogram = stingray.AveragedPowerspectrum( events, @@ -88,12 +86,8 @@ def test_distributed_pds(): def test_distributed_cpds(): - events1 = EventList( - np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]]) - ) - events2 = EventList( - np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]]) - ) + events1 = EventList(np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]])) + events2 = EventList(np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]])) if hasattr(stingray.AveragedCrossspectrum, "from_events"): single_periodogram = stingray.AveragedCrossspectrum( events1, @@ -108,9 +102,7 @@ def test_distributed_cpds(): events1, events2, segment_size=100, dt=0.1, norm="leahy" ) - pds_iterable = hen.fspec._provide_cross_periodograms( - events1, events2, 100, 0.1, "leahy" - ) + pds_iterable = hen.fspec._provide_cross_periodograms(events1, events2, 100, 0.1, "leahy") pds_distr = hen.fspec.average_periodograms(pds_iterable) assert np.allclose(pds_distr.power, single_periodogram.power) assert np.allclose(pds_distr.freq, single_periodogram.freq) @@ -135,12 +127,8 @@ def setup_class(cls): cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) - cls.ev_fileB = os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) for fname in [cls.ev_fileA, cls.ev_fileB]: if os.path.exists(fname): os.unlink(fname) @@ -170,17 +158,13 @@ def setup_class(cls): "monol_test_nustar_fpm_3-50keV_cpds" + HEN_FILE_EXTENSION, ) - command = ( - "{} {} -f 128 -k PDS --save-all --norm leahy --emin 3 --emax 50".format( - cls.ev_fileA, cls.ev_fileB - ) + command = "{} {} -f 128 -k PDS --save-all --norm leahy --emin 3 --emax 50".format( + cls.ev_fileA, cls.ev_fileB ) hen.fspec.main(command.split()) - command = ( - "{} {} -f 128 -k CPDS --save-all --norm leahy --emin 3 --emax 50".format( - cls.ev_fileA, cls.ev_fileB - ) + command = "{} {} -f 128 -k CPDS --save-all --norm leahy --emin 3 --emax 50".format( + cls.ev_fileA, cls.ev_fileB ) hen.fspec.main(command.split()) @@ -191,15 +175,12 @@ def test_pds_leahy_emax_only(self): """Test PDS production.""" evdata = self.ev_fileA - command = "{0} -f 128 -k PDS --save-all --norm leahy -b {1} --emax 50".format( - evdata, 1 - ) + command = "{0} -f 128 -k PDS --save-all --norm leahy -b {1} --emax 50".format(evdata, 1) hen.fspec.main(command.split()) out = os.path.join( self.datadir, - f"monol_testA_nustar_fpma_{HENDRICS_STAR_VALUE}-50keV_pds" - + HEN_FILE_EXTENSION, + f"monol_testA_nustar_fpma_{HENDRICS_STAR_VALUE}-50keV_pds" + HEN_FILE_EXTENSION, ) assert os.path.exists(out) io.remove_pds(out) @@ -208,15 +189,12 @@ def test_pds_leahy_emin_only(self): """Test PDS production.""" evdata = self.ev_fileA - command = "{0} -f 128 -k PDS --save-all --norm leahy -b {1} --emin 3".format( - evdata, 1 - ) + command = "{0} -f 128 -k PDS --save-all --norm leahy -b {1} --emin 3".format(evdata, 1) hen.fspec.main(command.split()) out = os.path.join( self.datadir, - f"monol_testA_nustar_fpma_3-{HENDRICS_STAR_VALUE}keV_pds" - + HEN_FILE_EXTENSION, + f"monol_testA_nustar_fpma_3-{HENDRICS_STAR_VALUE}keV_pds" + HEN_FILE_EXTENSION, ) assert os.path.exists(out) io.remove_pds(out) @@ -270,11 +248,7 @@ def test_cpds_leahy_lombscargle(self): command = f"{evdata1} {evdata2} -k CPDS --norm leahy --lombscargle -b -1" hen.fspec.main(command.split()) - evout = ( - evdata1.replace("fpma", "fpm") - .replace("testA", "test") - .replace("_ev", "_LS_cpds") - ) + evout = evdata1.replace("fpma", "fpm").replace("testA", "test").replace("_ev", "_LS_cpds") assert os.path.exists(evout) evpds = hen.io.load_pds(evout) io.remove_pds(evout) @@ -311,12 +285,8 @@ def test_pds(self, data_kind, lombscargle): else: label = "_lc" - outA = os.path.join( - self.datadir, f"monol_testA_nustar_fpma_pds" + HEN_FILE_EXTENSION - ) - outB = os.path.join( - self.datadir, f"monol_testB_nustar_fpmb_pds" + HEN_FILE_EXTENSION - ) + outA = os.path.join(self.datadir, f"monol_testA_nustar_fpma_pds" + HEN_FILE_EXTENSION) + outB = os.path.join(self.datadir, f"monol_testB_nustar_fpmb_pds" + HEN_FILE_EXTENSION) if lombscargle: outA = outA.replace("pds", "LS_pds") outB = outB.replace("pds", "LS_pds") @@ -330,10 +300,8 @@ def test_pds(self, data_kind, lombscargle): opts += " --lombscargle" command = "{0} {1} {2}".format( opts, - os.path.join(self.datadir, f"monol_testA_nustar_fpma{label}") - + HEN_FILE_EXTENSION, - os.path.join(self.datadir, f"monol_testB_nustar_fpmb{label}") - + HEN_FILE_EXTENSION, + os.path.join(self.datadir, f"monol_testA_nustar_fpma{label}") + HEN_FILE_EXTENSION, + os.path.join(self.datadir, f"monol_testB_nustar_fpmb{label}") + HEN_FILE_EXTENSION, ) hen.fspec.main(command.split()) @@ -362,18 +330,12 @@ def test_ignore_gti(self, data_kind): label = "_lc" command = "{0} {1} -f 128 --ignore-gtis".format( - os.path.join(self.datadir, f"monol_testA_nustar_fpma{label}") - + HEN_FILE_EXTENSION, - os.path.join(self.datadir, f"monol_testB_nustar_fpmb{label}") - + HEN_FILE_EXTENSION, + os.path.join(self.datadir, f"monol_testA_nustar_fpma{label}") + HEN_FILE_EXTENSION, + os.path.join(self.datadir, f"monol_testB_nustar_fpmb{label}") + HEN_FILE_EXTENSION, ) hen.fspec.main(command.split()) - outA = os.path.join( - self.datadir, f"monol_testA_nustar_fpma_pds" + HEN_FILE_EXTENSION - ) - outB = os.path.join( - self.datadir, f"monol_testB_nustar_fpmb_pds" + HEN_FILE_EXTENSION - ) + outA = os.path.join(self.datadir, f"monol_testA_nustar_fpma_pds" + HEN_FILE_EXTENSION) + outB = os.path.join(self.datadir, f"monol_testB_nustar_fpmb_pds" + HEN_FILE_EXTENSION) assert os.path.exists(outA) assert os.path.exists(outB) os.unlink(outA) @@ -407,13 +369,10 @@ def test_cpds_ignore_instr(self): def test_cpds_rms_norm(self): """Test CPDS production.""" - command = ( - "{0} {1} -f 128 --save-dyn -k CPDS --save-all " - "--norm rms -o {2}".format( - self.lcA, - self.lcB, - os.path.join(self.datadir, "monol_test_3-50keV_rms"), - ) + command = "{0} {1} -f 128 --save-dyn -k CPDS --save-all " "--norm rms -o {2}".format( + self.lcA, + self.lcB, + os.path.join(self.datadir, "monol_test_3-50keV_rms"), ) hen.fspec.main(command.split()) @@ -430,13 +389,10 @@ def test_cpds_wrong_norm(self): def test_cpds_dtbig(self): """Test CPDS production.""" - command = ( - "{0} {1} -f 128 --save-dyn -k CPDS --save-all --norm " - "frac -o {2}".format( - self.lcA, - self.lcB, - os.path.join(self.datadir, "monol_test_3-50keV_dtb"), - ) + command = "{0} {1} -f 128 --save-dyn -k CPDS --save-all --norm " "frac -o {2}".format( + self.lcA, + self.lcB, + os.path.join(self.datadir, "monol_test_3-50keV_dtb"), ) command += " -b 1" hen.fspec.main(command.split()) @@ -467,9 +423,7 @@ def test_sumpds(self): def test_dumpdyncpds(self): """Test dump dynamical PDSs.""" command = ( - "--noplot " - + os.path.join(self.datadir, "monol_test_3-50keV_cpds") - + HEN_FILE_EXTENSION + "--noplot " + os.path.join(self.datadir, "monol_test_3-50keV_cpds") + HEN_FILE_EXTENSION ) with pytest.raises(NotImplementedError): hen.fspec.dumpdyn_main(command.split()) @@ -477,8 +431,7 @@ def test_dumpdyncpds(self): def test_rebinpds(self): """Test PDS rebinning 1.""" command = "{0} -r 2".format( - os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds") - + HEN_FILE_EXTENSION + os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds") + HEN_FILE_EXTENSION ) hen.rebin.main(command.split()) os.path.exists( @@ -491,10 +444,8 @@ def test_rebinpds(self): def test_rebinpds_geom(self): """Test geometrical PDS rebinning.""" command = "{0} {1} -r 1.03".format( - os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds") - + HEN_FILE_EXTENSION, - os.path.join(self.datadir, "monol_testB_nustar_fpmb_3-50keV_pds") - + HEN_FILE_EXTENSION, + os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds") + HEN_FILE_EXTENSION, + os.path.join(self.datadir, "monol_testB_nustar_fpmb_3-50keV_pds") + HEN_FILE_EXTENSION, ) hen.rebin.main(command.split()) os.path.exists( @@ -513,8 +464,7 @@ def test_rebinpds_geom(self): def test_rebincpds(self): """Test CPDS rebinning.""" command = "{0} -r 2".format( - os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") - + HEN_FILE_EXTENSION + os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") + HEN_FILE_EXTENSION ) hen.rebin.main(command.split()) os.path.exists( @@ -527,8 +477,7 @@ def test_rebincpds(self): def test_rebincpds_geom(self): """Test CPDS geometrical rebinning.""" command = "{0} -r 1.03".format( - os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") - + HEN_FILE_EXTENSION + os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") + HEN_FILE_EXTENSION ) hen.rebin.main(command.split()) os.path.exists( @@ -564,17 +513,11 @@ def test_fit_pds(self): "monol_testB_nustar_fpmb_3-50keV_pds" + HEN_FILE_EXTENSION, ) - command = "{0} {1} -m {2} --frequency-interval 0 10".format( - pdsfile1, pdsfile2, modelfile - ) + command = "{0} {1} -m {2} --frequency-interval 0 10".format(pdsfile1, pdsfile2, modelfile) hen.modeling.main_model(command.split()) - out0 = os.path.join( - self.datadir, "monol_testA_nustar_fpma_3-50keV_pds_bestfit.p" - ) - out1 = os.path.join( - self.datadir, "monol_testB_nustar_fpmb_3-50keV_pds_bestfit.p" - ) + out0 = os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds_bestfit.p") + out1 = os.path.join(self.datadir, "monol_testB_nustar_fpmb_3-50keV_pds_bestfit.p") assert os.path.exists(out0) assert os.path.exists(out1) m, k, c = hen.io.load_model( @@ -615,9 +558,7 @@ def test_fit_cpds(self): with pytest.warns(ComplexWarning): hen.modeling.main_model(command.split()) - out0 = os.path.join( - self.datadir, "monol_test_nustar_fpm_3-50keV_cpds_bestfit.p" - ) + out0 = os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds_bestfit.p") assert os.path.exists(out0) m, k, c = hen.io.load_model(out0) assert hasattr(m, "amplitude") @@ -648,9 +589,7 @@ def test_fit_pds_f_no_of_intervals_invalid(self): "monol_testB_nustar_fpmb_3-50keV_pds" + HEN_FILE_EXTENSION, ) - command = "{0} {1} -m {2} --frequency-interval 0 1 9".format( - pdsfile1, pdsfile2, modelfile - ) + command = "{0} {1} -m {2} --frequency-interval 0 1 9".format(pdsfile1, pdsfile2, modelfile) with pytest.raises(ValueError, match="Invalid number of frequencies specified"): hen.modeling.main_model(command.split()) @@ -661,9 +600,7 @@ def test_savexspec(self): + HEN_FILE_EXTENSION ) hen.save_as_xspec.main(command.split()) - os.path.exists( - os.path.join(self.datadir, "monol_testA_nustar_fpmb_3-50keV_pds_rebin2.pha") - ) + os.path.exists(os.path.join(self.datadir, "monol_testA_nustar_fpmb_3-50keV_pds_rebin2.pha")) def test_savexspec_geom(self): """Test save as Xspec 2.""" @@ -696,10 +633,7 @@ def test_plot_lin(self): os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds_fit") + HEN_FILE_EXTENSION ) - lname = ( - os.path.join(self.datadir, "monol_testA_nustar_fpma_lc") - + HEN_FILE_EXTENSION - ) + lname = os.path.join(self.datadir, "monol_testA_nustar_fpma_lc") + HEN_FILE_EXTENSION hen.plot.main( [ pname, diff --git a/hendrics/tests/test_gti.py b/hendrics/tests/test_gti.py index d0d2d6e1..0f4d3a6d 100644 --- a/hendrics/tests/test_gti.py +++ b/hendrics/tests/test_gti.py @@ -37,17 +37,11 @@ class TestFullRun(object): def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) - cls.ev_fileB = os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, @@ -66,12 +60,8 @@ def setup_class(cls): cls.ev_fileA, cls.ev_fileB, os.path.join(cls.datadir, "test.rmf") ) hen.calibrate.main(command.split()) - cls.lcA = os.path.join( - os.path.join(cls.datadir, "monol_testA_lc" + HEN_FILE_EXTENSION) - ) - cls.lcB = os.path.join( - os.path.join(cls.datadir, "monol_testB_lc" + HEN_FILE_EXTENSION) - ) + cls.lcA = os.path.join(os.path.join(cls.datadir, "monol_testA_lc" + HEN_FILE_EXTENSION)) + cls.lcB = os.path.join(os.path.join(cls.datadir, "monol_testB_lc" + HEN_FILE_EXTENSION)) command = ("{} --nproc 2 -b 2 " "-o {}").format(cls.ev_fileAcal, cls.lcA) hen.lcurve.main(command.split()) command = ("{} --nproc 2 -b 2 " "-o {}").format(cls.ev_fileBcal, cls.lcB) @@ -79,10 +69,7 @@ def setup_class(cls): command = "{0} -f time>0 -c --debug".format(cls.ev_fileA) hen.create_gti.main(command.split()) - cls.gtifile = ( - os.path.join(cls.datadir, "monol_testA_nustar_fpma_gti") - + HEN_FILE_EXTENSION - ) + cls.gtifile = os.path.join(cls.datadir, "monol_testA_nustar_fpma_gti") + HEN_FILE_EXTENSION def test_create_gti(self): """Test creating a GTI file.""" @@ -92,9 +79,7 @@ def test_apply_gti(self): """Test applying a GTI file.""" fname = self.gtifile lcfname = self.ev_fileA - lcoutname = self.ev_fileA.replace( - HEN_FILE_EXTENSION, "_gtifilt" + HEN_FILE_EXTENSION - ) + lcoutname = self.ev_fileA.replace(HEN_FILE_EXTENSION, "_gtifilt" + HEN_FILE_EXTENSION) command = "{0} -a {1} --debug".format(lcfname, fname) hen.create_gti.main(command.split()) hen.io.load_events(lcoutname) diff --git a/hendrics/tests/test_io.py b/hendrics/tests/test_io.py index 469cd228..85d4e711 100644 --- a/hendrics/tests/test_io.py +++ b/hendrics/tests/test_io.py @@ -348,9 +348,7 @@ def test_load_and_save_cpds_all(self, fmt): pds.lc1 = Lightcurve(np.arange(2), [1, 2]) pds.lc2 = [Lightcurve(np.arange(2), [1, 2]), Lightcurve(np.arange(2), [3, 4])] - with pytest.warns( - UserWarning, match="Saving multiple light curves is not supported" - ): + with pytest.warns(UserWarning, match="Saving multiple light curves is not supported"): save_pds(pds, "bubup" + fmt, save_all=True) pds2 = load_pds("bubup" + fmt) for attr in [ @@ -604,9 +602,7 @@ def test_load_python_model_Astropy(self): def test_load_model_input_not_string(self): """Input is not a string""" - with pytest.raises( - TypeError, match="modelstring has to be an existing file name" - ): + with pytest.raises(TypeError, match="modelstring has to be an existing file name"): b, kind, _ = load_model(1) def test_load_model_input_file_doesnt_exist(self): diff --git a/hendrics/tests/test_lc.py b/hendrics/tests/test_lc.py index 60c898f8..83fb4e72 100644 --- a/hendrics/tests/test_lc.py +++ b/hendrics/tests/test_lc.py @@ -60,9 +60,7 @@ def test_treat_event_file_nustar(self): treat_event_file(self.fits_fileA, discard_calibration=True) lcurve_from_events(self.new_filename) - newfile = os.path.join( - self.datadir, "monol_testA_nustar_fpma_lc" + HEN_FILE_EXTENSION - ) + newfile = os.path.join(self.datadir, "monol_testA_nustar_fpma_lc" + HEN_FILE_EXTENSION) assert os.path.exists(newfile) type, data = get_file_type(newfile) assert type == "lc" @@ -111,12 +109,8 @@ def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) - cls.ev_fileB = os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, @@ -132,12 +126,8 @@ def setup_class(cls): ) hen.read_events.main(command.split()) command = "{} {} -r {}".format( - os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ), - os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ), + os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), + os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "test.rmf"), ) hen.calibrate.main(command.split()) @@ -149,9 +139,9 @@ def test_lcurve(self): new_filename = os.path.join( os.path.join(self.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) ) - command = ( - "{0} -e {1} {2} --safe-interval " "{3} {4} --nproc 2 -b 0.5 -o {5}" - ).format(self.ev_fileAcal, 3, 50, 100, 300, new_filename) + command = ("{0} -e {1} {2} --safe-interval " "{3} {4} --nproc 2 -b 0.5 -o {5}").format( + self.ev_fileAcal, 3, 50, 100, 300, new_filename + ) hen.lcurve.main(command.split()) assert os.path.exists(new_filename) @@ -230,21 +220,15 @@ def test_fits_lcurve0(self): """Test light curves from FITS.""" lcurve_ftools_orig = os.path.join(self.datadir, "lcurveA.fits") - lcurve_ftools = os.path.join( - self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION - ) + lcurve_ftools = os.path.join(self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION) command = "{0} --outfile {1}".format( self.ev_fileAcal, os.path.join(self.datadir, "lcurve_lc") ) hen.lcurve.main(command.split()) - assert os.path.exists( - os.path.join(self.datadir, "lcurve_lc") + HEN_FILE_EXTENSION - ) + assert os.path.exists(os.path.join(self.datadir, "lcurve_lc") + HEN_FILE_EXTENSION) - command = "--fits-input {0} --outfile {1}".format( - lcurve_ftools_orig, lcurve_ftools - ) + command = "--fits-input {0} --outfile {1}".format(lcurve_ftools_orig, lcurve_ftools) hen.lcurve.main(command.split()) with pytest.warns(AstropyUserWarning, match="File exists, and noclobber"): command = command + " --noclobber" @@ -252,9 +236,7 @@ def test_fits_lcurve0(self): def test_fits_lcurve1(self): """Test light curves from FITS.""" - lcurve_ftools = os.path.join( - self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION - ) + lcurve_ftools = os.path.join(self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION) lcurve_mp = os.path.join(self.datadir, "lcurve_lc" + HEN_FILE_EXTENSION) @@ -270,9 +252,7 @@ def test_fits_lcurve1(self): diff = lc_mp[:goodlen] - lc_ftools[:goodlen] - assert np.all( - np.abs(diff) <= 1e-3 - ), "Light curve data do not coincide between FITS and HEN" + assert np.all(np.abs(diff) <= 1e-3), "Light curve data do not coincide between FITS and HEN" def test_txt_lcurve(self): """Test light curves from txt.""" @@ -302,9 +282,7 @@ def test_txt_lcurve(self): def test_joinlcs(self): """Test produce joined light curves.""" - new_filename = os.path.join( - self.datadir, "monol_test_joinlc" + HEN_FILE_EXTENSION - ) + new_filename = os.path.join(self.datadir, "monol_test_joinlc" + HEN_FILE_EXTENSION) # because join_lightcurves separates by instrument new_actual_filename = os.path.join( self.datadir, "fpmamonol_test_joinlc" + HEN_FILE_EXTENSION @@ -358,9 +336,7 @@ def testbaselinelc_nooutroot(self): command = "{0} -p 0.001 --lam 1e5".format(a_in) hen.lcurve.baseline_main(command.split()) - out_lc = hen.io.load_lcurve( - hen.base.hen_root(a_in) + "_lc_baseline" + HEN_FILE_EXTENSION - ) + out_lc = hen.io.load_lcurve(hen.base.hen_root(a_in) + "_lc_baseline" + HEN_FILE_EXTENSION) assert hasattr(out_lc, "base") gti_to_test = hen.io.load_events(self.ev_fileA).gti assert np.allclose(gti_to_test, out_lc.gti) @@ -431,13 +407,8 @@ def test_create_gti_lc(self): def test_apply_gti_lc(self): """Test applying a GTI file.""" fname = os.path.join(self.datadir, "monol_testA_E3-50_gti") + HEN_FILE_EXTENSION - lcfname = ( - os.path.join(self.datadir, "monol_testA_E3-50_lc") + HEN_FILE_EXTENSION - ) - lcoutname = ( - os.path.join(self.datadir, "monol_testA_E3-50_lc_gtifilt") - + HEN_FILE_EXTENSION - ) + lcfname = os.path.join(self.datadir, "monol_testA_E3-50_lc") + HEN_FILE_EXTENSION + lcoutname = os.path.join(self.datadir, "monol_testA_E3-50_lc_gtifilt") + HEN_FILE_EXTENSION command = "{0} -a {1} --debug".format(lcfname, fname) hen.create_gti.main(command.split()) hen.io.load_lcurve(lcoutname) @@ -452,9 +423,7 @@ def test_plot_lcurve_baseline(self): def test_pds_fits(self): """Test PDS production with light curves obtained from FITS files.""" - lcurve_ftools = os.path.join( - self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION - ) + lcurve_ftools = os.path.join(self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION) command = "{0} --save-all -f 128".format(lcurve_ftools) hen.fspec.main(command.split()) @@ -471,9 +440,7 @@ def test_exposure(self): command = "{0} {1}".format(lcname, ufname) hen.exposure.main(command.split()) - fname = os.path.join( - self.datadir, "monol_testA_E3-50_lccorr" + HEN_FILE_EXTENSION - ) + fname = os.path.join(self.datadir, "monol_testA_E3-50_lccorr" + HEN_FILE_EXTENSION) assert os.path.exists(fname) ftype, contents = hen.io.get_file_type(fname) diff --git a/hendrics/tests/test_phaseogram.py b/hendrics/tests/test_phaseogram.py index 79fa2fc3..b463d424 100644 --- a/hendrics/tests/test_phaseogram.py +++ b/hendrics/tests/test_phaseogram.py @@ -122,9 +122,7 @@ def test_phaseogram_input_periodogram(self, label): ] ) - @pytest.mark.parametrize( - "norm", ["to1", "mediansub", "mediannorm", "meansub", "meannorm"] - ) + @pytest.mark.parametrize("norm", ["to1", "mediansub", "mediannorm", "meansub", "meannorm"]) def test_phaseogram_input_norm(self, norm): evfile = self.dum main_phaseogram( @@ -199,9 +197,7 @@ def test_phaseogram_deorbit(self, withfX): withbt = not withfX create_parfile(par, withfX=withfX, withell1=withell1, withbt=withbt) - ip = run_interactive_phaseogram( - evfile, 9.9, test=True, nbin=16, nt=8, deorbit_par=par - ) + ip = run_interactive_phaseogram(evfile, 9.9, test=True, nbin=16, nt=8, deorbit_par=par) ip.update(1) with warnings.catch_warnings(record=True) as ws: ip.recalculate(1) @@ -274,9 +270,7 @@ def test_phaseogram_input_f_change_binary_deorbit(self, use_ell1): evfile = self.dum par = "orbit.par" create_parfile(par, withell1=use_ell1, withbt=not use_ell1) - ip = run_interactive_phaseogram( - evfile, 9.9, test=True, binary=True, deorbit_par=par - ) + ip = run_interactive_phaseogram(evfile, 9.9, test=True, binary=True, deorbit_par=par) ip.update(1) with warnings.catch_warnings(record=True) as ws: ip.recalculate(1) diff --git a/hendrics/tests/test_phasetag.py b/hendrics/tests/test_phasetag.py index cfb9a5cf..048ce96a 100644 --- a/hendrics/tests/test_phasetag.py +++ b/hendrics/tests/test_phasetag.py @@ -120,9 +120,7 @@ def test_phase_tag_invalid1(self): ) def test_phase_tag_parfile(self): - with pytest.raises( - NotImplementedError, match="This part is not yet implemented" - ): + with pytest.raises(NotImplementedError, match="This part is not yet implemented"): main_phasetag([self.fits_fileA, "--parfile", "bubu.par", "--test"]) @classmethod diff --git a/hendrics/tests/test_read_events.py b/hendrics/tests/test_read_events.py index 53916cc9..b13113e2 100644 --- a/hendrics/tests/test_read_events.py +++ b/hendrics/tests/test_read_events.py @@ -226,12 +226,8 @@ def setup_class(cls): cls.fits_file, ] ) - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) - cls.ev_fileB = os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) def test_start(self): """Make any warnings in setup_class be dumped here.""" @@ -258,9 +254,7 @@ def test_treat_event_file_xmm(self): assert "pi" in data and data["pi"].size > 0 def test_treat_event_file_xte_se(self): - treat_event_file( - self.fits_file_xte, split_by_detector=False, bin_time_for_occultations=1 - ) + treat_event_file(self.fits_file_xte, split_by_detector=False, bin_time_for_occultations=1) new_filename = "xte_test_xte_pca_ev" + HEN_FILE_EXTENSION assert os.path.exists(os.path.join(self.datadir, new_filename)) data = load_data(os.path.join(self.datadir, new_filename)) @@ -319,9 +313,7 @@ def test_treat_event_file_xmm_lensplit(self): def test_split_events(self): treat_event_file(self.fits_fileA) - filea = os.path.join( - self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) + filea = os.path.join(self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) files = hen.read_events.main_splitevents([filea, "-l", "50"]) for f in files: @@ -330,16 +322,12 @@ def test_split_events(self): def test_split_events_at_mjd(self): treat_event_file(self.fits_fileA) - filea = os.path.join( - self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) + filea = os.path.join(self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) data = load_events(filea) mean_met = np.mean(data.time) mean_mjd = mean_met / 86400 + data.mjdref - files = hen.read_events.main_splitevents( - [filea, "--split-at-mjd", f"{mean_mjd}"] - ) + files = hen.read_events.main_splitevents([filea, "--split-at-mjd", f"{mean_mjd}"]) assert "before" in files[0] assert "after" in files[1] @@ -351,9 +339,7 @@ def test_split_events_at_mjd(self): def test_split_events_bad_overlap_raises(self): treat_event_file(self.fits_fileA) - filea = os.path.join( - self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) + filea = os.path.join(self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) with pytest.raises(ValueError, match="Overlap cannot be >=1. Exiting."): hen.read_events.split_eventlist(filea, 10, overlap=1.5) diff --git a/hendrics/timelags.py b/hendrics/timelags.py index 9c16dccf..40369c76 100644 --- a/hendrics/timelags.py +++ b/hendrics/timelags.py @@ -10,9 +10,7 @@ def main(args=None): import argparse from .base import _add_default_args - description = ( - "Read timelags from cross spectrum results and save them" " to a qdp file" - ) + description = "Read timelags from cross spectrum results and save them" " to a qdp file" parser = argparse.ArgumentParser(description=description) parser.add_argument("files", help="List of files", nargs="+") diff --git a/hendrics/varenergy.py b/hendrics/varenergy.py index e6d5af06..5fbadb56 100644 --- a/hendrics/varenergy.py +++ b/hendrics/varenergy.py @@ -158,9 +158,7 @@ def main(args=None): default=None, help="Reference band when relevant", ) - parser.add_argument( - "--rms", default=False, action="store_true", help="Calculate rms" - ) + parser.add_argument("--rms", default=False, action="store_true", help="Calculate rms") parser.add_argument( "--covariance", default=False, @@ -266,8 +264,7 @@ def main(args=None): if fname2 is not None: events2 = load_events(fname2) if not args.use_pi and ( - events.energy is None - or (events2 is not None and events2.energy is None) + events.energy is None or (events2 is not None and events2.energy is None) ): raise ValueError( "If --use-pi is not specified, event lists must " From 88b9136d0808c17d37ca8d29fe98cb8794307185 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 12:17:52 +0200 Subject: [PATCH 16/58] Reformat --- docs/conf.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 509ffa46..08d7e702 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Licensed under a 3-clause BSD style license - see LICENSE.rst # # Astropy documentation build configuration file. @@ -25,9 +24,9 @@ # Thus, any C-extensions that are needed to build the documentation will *not* # be accessible, and the documentation will not build correctly. +import datetime import os import sys -import datetime from importlib import import_module try: @@ -135,7 +134,7 @@ # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -html_title = "{0} v{1}".format(project, release) +html_title = f"{project} v{release}" # Output file base name for HTML help builder. htmlhelp_basename = project + "doc" From 9b38f658170d72a5792d8fd3d20029abeb60da78 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 12:18:24 +0200 Subject: [PATCH 17/58] reformat --- notebooks/deadtime_model_zhang.py | 93 +++++++++++++++++++------------ 1 file changed, 56 insertions(+), 37 deletions(-) diff --git a/notebooks/deadtime_model_zhang.py b/notebooks/deadtime_model_zhang.py index f22c1625..f36b0dc9 100644 --- a/notebooks/deadtime_model_zhang.py +++ b/notebooks/deadtime_model_zhang.py @@ -1,10 +1,12 @@ -from stingray.utils import jit from math import gamma -import numpy as np + import matplotlib.pyplot as plt +import numpy as np +from stingray.utils import jit from hendrics.base import r_det + @jit(nopython=True) def sum(x): s = 0 @@ -12,25 +14,30 @@ def sum(x): s += el return s + @jit(nopython=True) def factorial(n): return gamma(n + 1) + @jit(nopython=True) def fn(x, n): - return(x**(n-1) / factorial(n - 1)) * np.exp(-x) + return (x ** (n - 1) / factorial(n - 1)) * np.exp(-x) + @jit(nopython=True) def gn(x, n): return sum([fn(x, l) for l in range(1, n + 1)]) + @jit(nopython=True) def Gn_back(x, n): return sum([gn(x, l) for l in range(1, n)]) + @jit(nopython=True) def Gn(x, n): - return np.exp(-x) * sum([(n - l) / factorial(l) * x**l for l in range(0, n)]) + return np.exp(-x) * sum([(n - l) / factorial(l) * x**l for l in range(n)]) @jit(nopython=True) @@ -40,50 +47,57 @@ def heaviside(x): else: return 0 + @jit(nopython=True) def h(k, n, td, tb, tau): - # Typo in Zhang+95 corrected. k * tb, not k * td + # Typo in Zhang+95 corrected. k * tb, not k * td if k * tb < n * td: return 0 - return (k - n*(td + tau) / tb + - tau / tb * Gn((k * tb - n * td)/tau, n)) + return k - n * (td + tau) / tb + tau / tb * Gn((k * tb - n * td) / tau, n) + INFINITE = 100 + + @jit(nopython=True) def A(k, r0, td, tb, tau): if k == 0: return r0 * tb * (1 + 2 * sum([h(1, n, td, tb, tau) for n in range(1, INFINITE)])) - eq39_sums = [h(k + 1, n, td, tb, tau) - 2 * h(k, n, td, tb, tau) + h(k - 1, n, td, tb, tau) - for n in range(1, INFINITE)] + eq39_sums = [ + h(k + 1, n, td, tb, tau) - 2 * h(k, n, td, tb, tau) + h(k - 1, n, td, tb, tau) + for n in range(1, INFINITE) + ] return r0 * tb * sum(eq39_sums) + def safe_A(k, r0, td, tb, tau, limit_k=60): if k > limit_k: - return r0 ** 2 * tb**2 + return r0**2 * tb**2 return A(k, r0, td, tb, tau) + def check_A(rate, td, tb, max_k=100): """Ak ->r0**2tb**2 for k->infty""" tau = 1 / rate r0 = r_det(td, rate) - value = r0 ** 2 * tb**2 + value = r0**2 * tb**2 fig = plt.figure() for k in range(max_k): - plt.scatter(k, A(k, r0, td, tb, tau), color='k') - plt.axhline(value, ls='--', color='k') - plt.xlabel('$k$') - plt.ylabel('$A_k$') - plt.savefig('check_A.png') + plt.scatter(k, A(k, r0, td, tb, tau), color="k") + plt.axhline(value, ls="--", color="k") + plt.xlabel("$k$") + plt.ylabel("$A_k$") + plt.savefig("check_A.png") plt.close(fig) def B(k, r0, td, tb, tau): if k == 0: - return 2 * (A(0, r0, td, tb, tau) - r0**2 * tb**2) / (r0*tb) + return 2 * (A(0, r0, td, tb, tau) - r0**2 * tb**2) / (r0 * tb) - return 4 * (A(k, r0, td, tb, tau) - r0**2 * tb**2) / (r0*tb) + return 4 * (A(k, r0, td, tb, tau) - r0**2 * tb**2) / (r0 * tb) def safe_B(k, r0, td, tb, tau, limit_k=60): @@ -99,10 +113,10 @@ def check_B(rate, td, tb, max_k=100): plt.figure() for k in range(max_k): - plt.scatter(k, B(k, r0, td, tb, tau), color='k') - plt.axhline(0, ls='--', color='k') - plt.xlabel('$k$') - plt.ylabel('$B_k$') + plt.scatter(k, B(k, r0, td, tb, tau), color="k") + plt.axhline(0, ls="--", color="k") + plt.xlabel("$k$") + plt.ylabel("$B_k$") def pds_model_zhang_back(N, rate, td, tb, limit_k=60): @@ -110,12 +124,13 @@ def pds_model_zhang_back(N, rate, td, tb, limit_k=60): r0 = r_det(td, rate) Nph = N / tau P = np.zeros(N // 2) - for j in range(N//2): - eq8_sums = [(N - k) * safe_A(k, r0, td, tb, tau) * np.cos(2 * np.pi * j * k / N) - for k in range(1, N)] + for j in range(N // 2): + eq8_sums = [ + (N - k) * safe_A(k, r0, td, tb, tau) * np.cos(2 * np.pi * j * k / N) + for k in range(1, N) + ] - P[j] = 2 / Nph * (N * safe_A(0, r0, td, tb, tau, limit_k=limit_k) + - 2 * sum(eq8_sums)) + P[j] = 2 / Nph * (N * safe_A(0, r0, td, tb, tau, limit_k=limit_k) + 2 * sum(eq8_sums)) maxf = 0.5 / tb df = maxf / len(P) @@ -123,17 +138,21 @@ def pds_model_zhang_back(N, rate, td, tb, limit_k=60): return freqs, P + def pds_model_zhang(N, rate, td, tb, limit_k=60): tau = 1 / rate r0 = r_det(td, rate) Nph = N / tau P = np.zeros(N // 2) - for j in range(N//2): - eq8_sums = [(N - k) / N * - safe_B(k, r0, td, tb, tau, - limit_k=limit_k) * np.cos(2 * np.pi * j * k / N) - for k in range(1, N)] + for j in range(N // 2): + eq8_sums = [ + (N - k) + / N + * safe_B(k, r0, td, tb, tau, limit_k=limit_k) + * np.cos(2 * np.pi * j * k / N) + for k in range(1, N) + ] P[j] = safe_B(0, r0, td, tb, tau) + sum(eq8_sums) @@ -143,16 +162,16 @@ def pds_model_zhang(N, rate, td, tb, limit_k=60): return freqs, P + def check_pds_rate(td, tb, N=100): """P -> 2 for rate -> 0, or tau -> infty""" - plt.figure() for rate in np.logspace(2, -2, 5): p = pds_model_zhang_back(N, rate, td, tb)[1][1:] - plt.scatter(1/rate, np.max(np.abs(p)), color='k') + plt.scatter(1 / rate, np.max(np.abs(p)), color="k") p = pds_model_zhang(N, rate, td, tb)[1][1:] - plt.scatter(1/rate, np.max(np.abs(p)), color='b') + plt.scatter(1 / rate, np.max(np.abs(p)), color="b") - plt.xlabel(r'$\tau$') - plt.ylabel(r'Max($P_j$)') + plt.xlabel(r"$\tau$") + plt.ylabel(r"Max($P_j$)") plt.loglog() From ddc4b3a63cbcfac011382c61d56abb9996b93a67 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 12:32:22 +0200 Subject: [PATCH 18/58] Ruff it up --- hendrics/__init__.py | 12 +- hendrics/base.py | 82 ++++++----- hendrics/binary.py | 65 +++++---- hendrics/calibrate.py | 6 +- hendrics/colors.py | 14 +- hendrics/compat/__init__.py | 8 +- hendrics/compat/compatibility.py | 21 ++- hendrics/conftest.py | 2 - hendrics/create_gti.py | 42 ++++-- hendrics/efsearch.py | 203 ++++++++++++++++---------- hendrics/exposure.py | 45 ++++-- hendrics/exvar.py | 9 +- hendrics/fake.py | 61 +++++--- hendrics/ffa.py | 23 +-- hendrics/fold.py | 101 ++++++++----- hendrics/fspec.py | 50 ++++--- hendrics/io.py | 127 ++++++++-------- hendrics/lcurve.py | 80 ++++++---- hendrics/ml_timing.py | 16 +- hendrics/modeling.py | 13 +- hendrics/phaseogram.py | 140 +++++++++++------- hendrics/phasetag.py | 47 ++++-- hendrics/plot.py | 124 ++++++++++------ hendrics/power_colors.py | 17 ++- hendrics/read_events.py | 75 ++++++---- hendrics/rebin.py | 6 +- hendrics/save_as_xspec.py | 12 +- hendrics/setup_package.py | 2 +- hendrics/sum_fspec.py | 8 +- hendrics/tests/__init__.py | 2 +- hendrics/tests/test_a_complete_run.py | 99 ++++++------- hendrics/tests/test_base.py | 11 +- hendrics/tests/test_binary.py | 38 +++-- hendrics/tests/test_calibrate.py | 37 +++-- hendrics/tests/test_colors.py | 63 +++----- hendrics/tests/test_efsearch.py | 56 ++++--- hendrics/tests/test_exposure.py | 1 + hendrics/tests/test_fake.py | 59 ++++---- hendrics/tests/test_ffa.py | 14 +- hendrics/tests/test_fspec.py | 186 +++++++++++++---------- hendrics/tests/test_gti.py | 53 ++++--- hendrics/tests/test_io.py | 65 +++++---- hendrics/tests/test_lc.py | 120 ++++++++------- hendrics/tests/test_ml_timing.py | 13 +- hendrics/tests/test_phaseogram.py | 42 ++++-- hendrics/tests/test_phasetag.py | 10 +- hendrics/tests/test_read_events.py | 58 +++++--- hendrics/timelags.py | 11 +- hendrics/varenergy.py | 21 +-- 49 files changed, 1418 insertions(+), 952 deletions(-) diff --git a/hendrics/__init__.py b/hendrics/__init__.py index 3c3787a6..f179338d 100644 --- a/hendrics/__init__.py +++ b/hendrics/__init__.py @@ -22,21 +22,21 @@ except ImportError: HEN_FILE_EXTENSION = ".p" HAS_NETCDF = False - pass - import stingray import warnings + import stingray + warnings.filterwarnings("ignore", message=".*Errorbars on cross.*") from .compat import ( - prange, - array_take, HAS_NUMBA, - njit, - vectorize, + array_take, float32, float64, int32, int64, + njit, + prange, + vectorize, ) diff --git a/hendrics/base.py b/hendrics/base.py index 02207289..4ddb8a0d 100644 --- a/hendrics/base.py +++ b/hendrics/base.py @@ -1,34 +1,38 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """A miscellaneous collection of basic functions.""" -import os.path -import sys import copy import os +import os.path +import sys +import tempfile import urllib import warnings from collections.abc import Iterable from pathlib import Path -import tempfile -from astropy.io.registry import identify_format -from astropy.table import Table -from scipy.interpolate import interp1d -from scipy.ndimage import gaussian_filter -from scipy.stats import ncx2 import numpy as np -from numpy import histogram2d as histogram2d_np from numpy import histogram as histogram_np -from astropy.logger import AstropyUserWarning -from astropy import log -from stingray.stats import pds_probability, pds_detection_level -from stingray.stats import z2_n_detection_level, z2_n_probability -from stingray.stats import fold_detection_level, fold_profile_probability +from numpy import histogram2d as histogram2d_np +from scipy.interpolate import interp1d +from scipy.ndimage import gaussian_filter from stingray.pulse.pulsar import _load_and_prepare_TOAs +from stingray.stats import ( + fold_detection_level, + fold_profile_probability, + pds_detection_level, + pds_probability, + z2_n_detection_level, + z2_n_probability, +) + +from astropy import log +from astropy.io.registry import identify_format +from astropy.table import Table try: - import pint.toa as toa import pint + import pint.toa as toa from pint.models import get_model HAS_PINT = True @@ -52,15 +56,10 @@ def show_progress(a): from . import ( - prange, - array_take, HAS_NUMBA, + array_take, njit, - vectorize, - float32, - float64, - int32, - int64, + prange, ) __all__ = [ @@ -254,7 +253,7 @@ def _look_for_array_in_array(array1, array2): def is_string(s): """Portable function to answer this question.""" - return isinstance(s, str) # NOQA + return isinstance(s, str) def _order_list_of_arrays(data, order): @@ -410,7 +409,7 @@ def simple_orbit_fun_from_parfile( parfile : str Any parameter file understood by PINT (Tempo or Tempo2 format) - Other parameters + Other Parameters ---------------- ntimes : int Number of time intervals to use for interpolation. Default 1000 @@ -423,7 +422,6 @@ def simple_orbit_fun_from_parfile( correction_mjd : function Function that accepts times in MJDs and returns the deorbited times. """ - from scipy.interpolate import interp1d from astropy import units if not HAS_PINT: @@ -461,10 +459,12 @@ def deorbit_events(events, parameter_file=None, invert=False, ephem=None): """ events = copy.deepcopy(events) if parameter_file is None: - warnings.warn("No parameter file specified for deorbit. Returning" " unaltered event list") + warnings.warn( + "No parameter file specified for deorbit. Returning" " unaltered event list" + ) return events if not os.path.exists(parameter_file): - raise FileNotFoundError("Parameter file {} does not exist".format(parameter_file)) + raise FileNotFoundError(f"Parameter file {parameter_file} does not exist") if events.mjdref < 33282.0: raise ValueError("MJDREF is very low (<01-01-1950), " "this is unsupported.") @@ -605,7 +605,6 @@ def compute_bin(x, bin_edges): >>> assert compute_bin(5, bin_edges) == 1 >>> assert compute_bin(10, bin_edges) == 1 """ - # assuming uniform bins for now n = bin_edges.shape[0] - 1 a_min = bin_edges[0] @@ -660,7 +659,9 @@ def hist1d_numba_seq(a, bins, ranges, use_memmap=False, tmp=None): if bins > 10**7 and use_memmap: if tmp is None: tmp = tempfile.NamedTemporaryFile("w+").name - hist_arr = np.lib.format.open_memmap(tmp, mode="w+", dtype=a.dtype, shape=(bins,)) + hist_arr = np.lib.format.open_memmap( + tmp, mode="w+", dtype=a.dtype, shape=(bins,) + ) else: hist_arr = np.zeros((bins,), dtype=a.dtype) @@ -693,7 +694,9 @@ def hist2d_numba_seq(x, y, bins, ranges): >>> assert np.all(H == Hn) """ H = np.zeros((bins[0], bins[1]), dtype=np.uint64) - return _hist2d_numba_seq(H, np.array([x, y]), np.asarray(list(bins)), np.asarray(ranges)) + return _hist2d_numba_seq( + H, np.array([x, y]), np.asarray(list(bins)), np.asarray(ranges) + ) @njit(nogil=True, parallel=False) @@ -723,9 +726,10 @@ def hist3d_numba_seq(tracks, bins, ranges): ... ranges=[[0., 1.], [2., 3.], [4., 5.]]) >>> assert np.all(H == Hn) """ - H = np.zeros((bins[0], bins[1], bins[2]), dtype=np.uint64) - return _hist3d_numba_seq(H, np.asarray(tracks), np.asarray(list(bins)), np.asarray(ranges)) + return _hist3d_numba_seq( + H, np.asarray(tracks), np.asarray(list(bins)), np.asarray(ranges) + ) @njit(nogil=True, parallel=False) @@ -766,7 +770,9 @@ def hist1d_numba_seq_weight(a, weights, bins, ranges, use_memmap=False, tmp=None if bins > 10**7 and use_memmap: if tmp is None: tmp = tempfile.NamedTemporaryFile("w+").name - hist_arr = np.lib.format.open_memmap(tmp, mode="w+", dtype=a.dtype, shape=(bins,)) + hist_arr = np.lib.format.open_memmap( + tmp, mode="w+", dtype=a.dtype, shape=(bins,) + ) else: hist_arr = np.zeros((bins,), dtype=a.dtype) @@ -841,7 +847,6 @@ def hist3d_numba_seq_weight(tracks, weights, bins, ranges): ... ranges=[[0., 1.], [2., 3.], [4., 5.]]) >>> assert np.all(H == Hn) """ - H = np.zeros((bins[0], bins[1], bins[2]), dtype=np.double) return _hist3d_numba_seq_weight( H, @@ -872,7 +877,10 @@ def _histnd_numba_seq(H, tracks, bins, ranges, slice_int): for t in range(tracks.shape[1]): slicearr = np.array( - [(tracks[dim, t] - ranges[dim, 0]) * delta[dim] for dim in range(tracks.shape[0])] + [ + (tracks[dim, t] - ranges[dim, 0]) * delta[dim] + for dim in range(tracks.shape[0]) + ] ) good = np.all((slicearr < bins) & (slicearr >= 0)) @@ -1145,7 +1153,8 @@ def find_peaks_in_image(image, n=5, rough=False, **kwargs): """ if not HAS_SKIMAGE or rough: best_cands = [ - np.unravel_index(idx, image.shape) for idx in np.argpartition(image.flatten(), -n)[-n:] + np.unravel_index(idx, image.shape) + for idx in np.argpartition(image.flatten(), -n)[-n:] ] __best_stats = [image[bci] for bci in best_cands] best_cands = np.asarray(best_cands)[np.argsort(__best_stats)][::-1] @@ -1271,7 +1280,6 @@ def get_file_extension(fname): >>> get_file_extension('bu.fits.Gz') '.fits.Gz' """ - raw_ext = os.path.splitext(fname)[1] if raw_ext.lower() in [".gz", ".bz", ".z", ".bz2"]: fname = fname.replace(raw_ext, "") diff --git a/hendrics/binary.py b/hendrics/binary.py index dbc8dc83..faf5dce7 100644 --- a/hendrics/binary.py +++ b/hendrics/binary.py @@ -1,10 +1,12 @@ """Save different input files in PRESTO-readable format.""" +import numpy as np + from astropy import log from astropy.coordinates import SkyCoord -import numpy as np -from .io import high_precision_keyword_read, get_file_type, HEN_FILE_EXTENSION + from .base import deorbit_events, interpret_bintime +from .io import HEN_FILE_EXTENSION, get_file_type, high_precision_keyword_read MAXBIN = 100000000 @@ -35,7 +37,12 @@ def get_header_info(obj): dec = header["DEC_PNT"] a = SkyCoord(ra, dec, unit="degree") - info.raj = (a.ra.to_string("hourangle")).replace("s", "").replace("h", ":").replace("m", ":") + info.raj = ( + (a.ra.to_string("hourangle")) + .replace("s", "") + .replace("h", ":") + .replace("m", ":") + ) info.decj = (a.dec.to_string()).replace("s", "").replace("d", ":").replace("m", ":") if hasattr(obj, "e_interval"): e0, e1 = obj.e_interval @@ -53,7 +60,6 @@ def _save_to_binary(lc, filename): """Save a light curve to binary format.""" nc = len(lc.counts) lc.counts[: nc // 2 * 2].astype("float32").tofile(filename) - return def save_lc_to_binary(lc, filename): @@ -65,6 +71,7 @@ def save_lc_to_binary(lc, filename): Input light curve filename : str Output file name + Returns ------- lcinfo : object @@ -87,7 +94,9 @@ def save_lc_to_binary(lc, filename): return lcinfo -def save_events_to_binary(events, filename, bin_time, tstart=None, emin=None, emax=None): +def save_events_to_binary( + events, filename, bin_time, tstart=None, emin=None, emax=None +): """Save an event list to binary format. Parameters @@ -99,7 +108,7 @@ def save_events_to_binary(events, filename, bin_time, tstart=None, emin=None, em bin_time : float Bin time of the output light curve - Other parameters + Other Parameters ---------------- tstart : float Starting time @@ -120,7 +129,9 @@ def save_events_to_binary(events, filename, bin_time, tstart=None, emin=None, em if emin is not None and emax is not None: if not hasattr(events, "energy") or events.energy is None: - raise ValueError("Energy filtering requested for uncalibrated event " "list") + raise ValueError( + "Energy filtering requested for uncalibrated event " "list" + ) good = (events.energy >= emin) & (events.energy < emax) events = events.apply_mask(good) @@ -162,7 +173,6 @@ def save_events_to_binary(events, filename, bin_time, tstart=None, emin=None, em def save_inf(lcinfo, info, filename): """Save information file.""" - lclen = lcinfo.lclen bin_intervals_start, bin_intervals_stop = ( lcinfo.bin_intervals_start, @@ -173,79 +183,80 @@ def save_inf(lcinfo, info, filename): with open(filename, "w") as f: print( - " Data file name without suffix " " = {}".format(filename.replace(".inf", "")), + " Data file name without suffix " " = {}".format( + filename.replace(".inf", "") + ), file=f, ) print( - " Telescope used " " = {}".format(info.telescope), + " Telescope used " f" = {info.telescope}", file=f, ) print( - " Instrument used " " = {}".format(info.instrument), + " Instrument used " f" = {info.instrument}", file=f, ) print( - " Object being observed " " = {}".format(info.source), + " Object being observed " f" = {info.source}", file=f, ) print( - " J2000 Right Ascension (hh:mm:ss.ssss) " " = {}".format(info.raj), + " J2000 Right Ascension (hh:mm:ss.ssss) " f" = {info.raj}", file=f, ) print( - " J2000 Declination (dd:mm:ss.ssss) " " = {}".format(info.decj), + " J2000 Declination (dd:mm:ss.ssss) " f" = {info.decj}", file=f, ) print( - " Data observed by " " = {}".format(info.observer), + " Data observed by " f" = {info.observer}", file=f, ) print( - " Epoch of observation (MJD) " " = {:05.15f}".format(epoch), + " Epoch of observation (MJD) " f" = {epoch:05.15f}", file=f, ) print(" Barycentered? (1=yes, 0=no) " " = 1", file=f) print( - " Number of bins in the time series " " = {lclen}".format(lclen=lclen), + " Number of bins in the time series " f" = {lclen}", file=f, ) print( - " Width of each time series bin (sec) " " = {bintime}".format(bintime=lcinfo.dt), + " Width of each time series bin (sec) " f" = {lcinfo.dt}", file=f, ) print(" Any breaks in the data? (1 yes, 0 no) " " = 1", file=f) for i, st in enumerate(bin_intervals_start): print( - " On/Off bin pair # {ngti:>2} " - " = {binstart:<11}, " - "{binstop:<11}".format(ngti=i + 1, binstart=st, binstop=bin_intervals_stop[i]), + f" On/Off bin pair # {i + 1:>2} " + f" = {st:<11}, " + f"{bin_intervals_stop[i]:<11}", file=f, ) print(" Type of observation (EM band) " " = X-ray", file=f) print(" Field-of-view diameter (arcsec) " " = 400", file=f) print( - " Central energy (kev) " " = {}".format(info.centralE), + " Central energy (kev) " f" = {info.centralE}", file=f, ) print( - " Energy bandpass (kev) " " = {}".format(info.bandpass), + " Energy bandpass (kev) " f" = {info.bandpass}", file=f, ) print( - " Data analyzed by " " = {}".format(info.user), + " Data analyzed by " f" = {info.user}", file=f, ) print(" Any additional notes:", file=f) print( - " T = {length}, Nphot={nphot}".format(length=lcinfo.tseg, nphot=lcinfo.nphot), + f" T = {lcinfo.tseg}, Nphot={lcinfo.nphot}", file=f, ) - return - def main_presto(args=None): import argparse + from .base import _add_default_args, check_negative_numbers_in_args description = "Save light curves in a format readable to PRESTO" diff --git a/hendrics/calibrate.py b/hendrics/calibrate.py index d9d38720..ad933b86 100644 --- a/hendrics/calibrate.py +++ b/hendrics/calibrate.py @@ -3,12 +3,13 @@ import os import warnings + import numpy as np + from astropy import log from .base import get_file_extension -from .io import load_events, save_events -from .io import HEN_FILE_EXTENSION +from .io import HEN_FILE_EXTENSION, load_events, save_events def default_nustar_rmf(): @@ -176,6 +177,7 @@ def main(args=None): """Main function called by the `HENcalibrate` command line script.""" import argparse from multiprocessing import Pool + from .base import _add_default_args description = ( diff --git a/hendrics/colors.py b/hendrics/colors.py index 49827673..8e59ee9b 100644 --- a/hendrics/colors.py +++ b/hendrics/colors.py @@ -1,12 +1,13 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """Functions to calculate colors and hardness.""" -import os -from astropy import log -from stingray.lightcurve import Lightcurve import numpy as np -from .io import HEN_FILE_EXTENSION, load_events, save_lcurve +from stingray.lightcurve import Lightcurve + +from astropy import log + from .base import hen_root +from .io import HEN_FILE_EXTENSION, load_events, save_lcurve def colors(): @@ -16,6 +17,7 @@ def colors(): def main(args=None): """Main function called by the `HENcolors` command line script.""" import argparse + from .base import _add_default_args, check_negative_numbers_in_args description = "Calculate color light curves" @@ -54,9 +56,9 @@ def main(args=None): events = load_events(f) if not args.use_pi and events.energy is None: raise ValueError( - "Energy information not found in file {0}. " + f"Energy information not found in file {f}. " "Use --use-pi if you want to use PI channels " - "instead.".format(f) + "instead." ) h_starts, h_stops, colors, color_errs = events.get_color_evolution( energy_ranges=energies, segment_size=args.bintime, use_pi=args.use_pi diff --git a/hendrics/compat/__init__.py b/hendrics/compat/__init__.py index ba27b1ef..94336e56 100644 --- a/hendrics/compat/__init__.py +++ b/hendrics/compat/__init__.py @@ -1,11 +1,11 @@ from .compatibility import ( - prange, - array_take, HAS_NUMBA, - njit, - vectorize, + array_take, float32, float64, int32, int64, + njit, + prange, + vectorize, ) diff --git a/hendrics/compat/compatibility.py b/hendrics/compat/compatibility.py index 5070220e..b432eb18 100644 --- a/hendrics/compat/compatibility.py +++ b/hendrics/compat/compatibility.py @@ -1,13 +1,20 @@ -from functools import wraps import warnings +from functools import wraps + import numpy as np -from astropy import log -from collections.abc import Iterable as iterable try: - from numba import jit, njit, prange, vectorize - from numba import float32, float64, int32, int64 - from numba import types + from numba import ( + float32, + float64, + int32, + int64, + jit, + njit, + prange, + types, + vectorize, + ) from numba.extending import overload_method HAS_NUMBA = True @@ -33,7 +40,7 @@ def prange(*args): """Dummy decorator in case jit cannot be imported.""" return range(*args) - class vectorize(object): + class vectorize: def __init__(self, *args, **kwargs): pass diff --git a/hendrics/conftest.py b/hendrics/conftest.py index 543d05d1..684a6ab3 100644 --- a/hendrics/conftest.py +++ b/hendrics/conftest.py @@ -5,8 +5,6 @@ import os -from astropy.version import version as astropy_version - try: from pytest_astropy_header.display import ( PYTEST_HEADER_MODULES, diff --git a/hendrics/create_gti.py b/hendrics/create_gti.py index fd4ff1b0..6d311987 100644 --- a/hendrics/create_gti.py +++ b/hendrics/create_gti.py @@ -3,16 +3,18 @@ import sys import warnings + import numpy as np -from astropy import log -from astropy.logger import AstropyUserWarning from stingray.gti import ( - cross_gtis, create_gti_from_condition, - create_gti_mask, + cross_gtis, ) -from .io import HEN_FILE_EXTENSION, save_data, load_data, get_file_type -from .base import hen_root, _assign_value_if_none + +from astropy import log +from astropy.logger import AstropyUserWarning + +from .base import _assign_value_if_none, hen_root +from .io import HEN_FILE_EXTENSION, get_file_type, load_data, save_data def filter_gti_by_length(gti, minimum_length): @@ -29,7 +31,9 @@ def filter_gti_by_length(gti, minimum_length): return np.array(newgti) -def create_gti(fname, filter_expr, safe_interval=[0, 0], outfile=None, minimum_length=0): +def create_gti( + fname, filter_expr, safe_interval=[0, 0], outfile=None, minimum_length=0 +): """Create a GTI list by using boolean operations on file data. Parameters @@ -45,7 +49,7 @@ def create_gti(fname, filter_expr, safe_interval=[0, 0], outfile=None, minimum_l gti : [[gti0_0, gti0_1], [gti1_0, gti1_1], ...] The newly created GTIs - Other parameters + Other Parameters ---------------- safe_interval : float or [float, float] A safe interval to exclude at both ends (if single float) or the start @@ -71,7 +75,9 @@ def create_gti(fname, filter_expr, safe_interval=[0, 0], outfile=None, minimum_l if hasattr(data, "internal_array_attrs"): array_attrs = data.internal_array_attrs() mod_array_attrs = [attr.replace("_", "") for attr in array_attrs] - locals().update(zip(mod_array_attrs, [getattr(data, attr) for attr in array_attrs])) + locals().update( + zip(mod_array_attrs, [getattr(data, attr) for attr in array_attrs]) + ) good = eval(filter_expr) @@ -79,7 +85,9 @@ def create_gti(fname, filter_expr, safe_interval=[0, 0], outfile=None, minimum_l gti = filter_gti_by_length(gti, minimum_length) - outfile = _assign_value_if_none(outfile, hen_root(fname) + "_gti" + HEN_FILE_EXTENSION) + outfile = _assign_value_if_none( + outfile, hen_root(fname) + "_gti" + HEN_FILE_EXTENSION + ) save_data({"gti": gti, "mjdref": mjdref, "__sr__class__type__": "gti"}, outfile) return gti @@ -106,7 +114,9 @@ def apply_gti(fname, gti, outname=None, minimum_length=0): data._mask = None newext = "_gtifilt" + HEN_FILE_EXTENSION - outname = _assign_value_if_none(outname, fname.replace(HEN_FILE_EXTENSION, "") + newext) + outname = _assign_value_if_none( + outname, fname.replace(HEN_FILE_EXTENSION, "") + newext + ) save_data(data, outname) return newgti @@ -115,10 +125,12 @@ def apply_gti(fname, gti, outname=None, minimum_length=0): def main(args=None): """Main function called by the `HENcreategti` command line script.""" import argparse + from .base import _add_default_args, check_negative_numbers_in_args description = ( - "Create GTI files from a filter expression, or applies " "previously created GTIs to a file" + "Create GTI files from a filter expression, or applies " + "previously created GTIs to a file" ) parser = argparse.ArgumentParser(description=description) @@ -139,7 +151,8 @@ def main(args=None): "--create-only", default=False, action="store_true", - help="If specified, creates GTIs without applying" + "them to files (Default: False)", + help="If specified, creates GTIs without applying" + + "them to files (Default: False)", ) parser.add_argument( @@ -187,7 +200,8 @@ def main(args=None): filter_expr = args.filter if filter_expr is None and args.apply_gti is None: sys.exit( - "Please specify filter expression (-f option) or input " "GTI file (-a option)" + "Please specify filter expression (-f option) or input " + "GTI file (-a option)" ) for fname in files: diff --git a/hendrics/efsearch.py b/hendrics/efsearch.py index caf3c56b..9656afa3 100644 --- a/hendrics/efsearch.py +++ b/hendrics/efsearch.py @@ -1,51 +1,56 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """Search for pulsars.""" -import warnings -import os import argparse import copy +import os +import warnings import numpy as np from scipy.ndimage import gaussian_filter -from astropy import log -from astropy.table import Table, vstack -from astropy.logger import AstropyUserWarning -from .io import get_file_type +from stingray.gti import time_intervals_from_gtis +from stingray.pulse.modeling import fit_gaussian, fit_sinc from stingray.pulse.search import ( epoch_folding_search, z_n_search, - search_best_peaks, ) -from stingray.stats import a_from_ssig, pf_from_ssig, power_confidence_limits - -from stingray.gti import time_intervals_from_gtis -from stingray.utils import assign_value_if_none -from stingray.pulse.modeling import fit_sinc, fit_gaussian -from stingray.stats import pf_upper_limit -from .io import ( - load_events, - EFPeriodogram, - save_folding, - HEN_FILE_EXTENSION, - load_folding, +from stingray.stats import ( + a_from_ssig, + pf_upper_limit, + power_confidence_limits, ) +from stingray.utils import assign_value_if_none + +from astropy import log +from astropy.logger import AstropyUserWarning +from astropy.table import Table from .base import ( + HENDRICS_STAR_VALUE, + adjust_dt_for_power_of_two, + deorbit_events, + find_peaks_in_image, + fold_detection_level, hen_root, + histogram, + histogram2d, + memmapped_arange, + njit, + prange, show_progress, - adjust_dt_for_power_of_two, - HENDRICS_STAR_VALUE, + z2_n_detection_level, ) -from .base import deorbit_events, njit, prange, vectorize, float64 -from .base import histogram2d, histogram, memmapped_arange -from .base import z2_n_detection_level, fold_detection_level -from .base import find_peaks_in_image -from .base import z2_n_detection_level -from .base import fold_detection_level -from .fold import filter_energy -from .ffa import _z_n_fast_cached, ffa_search, h_test from .fake import scramble +from .ffa import _z_n_fast_cached, ffa_search, h_test +from .fold import filter_energy +from .io import ( + HEN_FILE_EXTENSION, + EFPeriodogram, + get_file_type, + load_events, + load_folding, + save_folding, +) try: import matplotlib.pyplot as plt @@ -130,7 +135,6 @@ def find_nearest_contour(cs, x, y, indices=None, pixel=True): d2 : float The squared distance from ``(xmin, ymin)`` to ``(x, y)``. """ - from matplotlib.contour import _find_closest_point_on_path # This function uses a method that is probably quite @@ -224,7 +228,7 @@ def decide_binary_parameters( ] df = 1 / length - log.info("Recommended frequency steps: {}".format(int(np.diff(freq_range)[0] // df + 1))) + log.info(f"Recommended frequency steps: {int(np.diff(freq_range)[0] // df + 1)}") while count < NMAX: # In any case, only the first loop deletes the file if count > 0: @@ -244,7 +248,9 @@ def decide_binary_parameters( Omegas = np.random.uniform(omega_range[0], omega_range[1], nOmega) for Omega in Omegas: - block_of_data.append([freq, fdot, X, TWOPI / Omega, False, 0.0, 0.0, 0.0]) + block_of_data.append( + [freq, fdot, X, TWOPI / Omega, False, 0.0, 0.0, 0.0] + ) df = pd.DataFrame(block_of_data, columns=columns) _save_df_to_csv(df, csv_file, reset=reset) @@ -287,8 +293,12 @@ def folding_orbital_search( for T0 in T0s: # one iteration new_values = times - X * np.sin(2 * np.pi * (times - T0) / Porb) - new_values = new_values - X * np.sin(2 * np.pi * (new_values - T0) / Porb) - fgrid, stats = fun(new_values, np.array([freq]), fdots=fdot, **fun_kwargs) + new_values = new_values - X * np.sin( + 2 * np.pi * (new_values - T0) / Porb + ) + fgrid, stats = fun( + new_values, np.array([freq]), fdots=fdot, **fun_kwargs + ) if stats[0] > max_stats: max_stats = stats[0] best_T0 = T0 @@ -341,7 +351,9 @@ def mod(num, n2): @njit() -def shift_and_sum(repeated_profiles, lshift, qshift, splat_prof, base_shift, quadbaseshift): +def shift_and_sum( + repeated_profiles, lshift, qshift, splat_prof, base_shift, quadbaseshift +): nprof = repeated_profiles.shape[0] nbin = splat_prof.size twonbin = nbin * 2 @@ -351,7 +363,9 @@ def shift_and_sum(repeated_profiles, lshift, qshift, splat_prof, base_shift, qua total_shift = mod(np.rint(total_shift), nbin) total_shift_int = int(total_shift) - splat_prof[:] += repeated_profiles[k, nbin - total_shift_int : twonbin - total_shift_int] + splat_prof[:] += repeated_profiles[ + k, nbin - total_shift_int : twonbin - total_shift_int + ] return splat_prof @@ -384,7 +398,6 @@ def z_n_fast(phase, norm, n=2): >>> assert np.isclose(z_n_fast(phase, norm, n=4), 50) >>> assert np.isclose(z_n_fast(phase, norm, n=2), 50) """ - total_norm = np.sum(norm) result = 0 @@ -408,6 +421,7 @@ def _average_and_z_sub_search(profiles, n=2): a M x N matrix containing a list of pulse profiles nbin : int The number of bins in the profiles. + Returns ------- z2_n : float array (MxM) @@ -462,7 +476,6 @@ def _transient_search_step( times: np.double, mean_f: np.double, mean_fdot=0, nbin=16, nprof=64, n=1 ): """Single step of transient search.""" - # Cast to standard double, or Numba's histogram2d will fail # horribly. @@ -479,7 +492,7 @@ def _transient_search_step( return n_ave, results -class TransientResults(object): +class TransientResults: oversample: int = None f0: float = None f1: float = None @@ -513,7 +526,7 @@ def transient_search( f1 : float Maximum frequency to search - Other parameters + Other Parameters ---------------- nbin : int Number of bins to divide the profile into @@ -551,7 +564,9 @@ def transient_search( times -= meantime maxerr = check_phase_error_after_casting_to_double(np.max(times), f1, fdot) - log.info(f"Maximum error on the phase expected when casting to double: " f"{maxerr}") + log.info( + f"Maximum error on the phase expected when casting to double: " f"{maxerr}" + ) if maxerr > 1 / nbin / 10: warnings.warn( "Casting to double produces non-negligible phase errors. " @@ -611,8 +626,8 @@ def transient_search( def plot_transient_search(results, gif_name=None): - import matplotlib.pyplot as plt import matplotlib + import matplotlib.pyplot as plt matplotlib.use("Agg") if gif_name is None: @@ -675,7 +690,9 @@ def plot_transient_search(results, gif_name=None): f"{gif_name}: Possible candidate at step {i}: {best_f} Hz (~{maxline:.1f} sigma)" ) elif maxline >= 5 and i_f == 0: # pragma: no cover - print(f"{gif_name}: Candidate at step {i}: {best_f} Hz (~{maxline:.1f} sigma)") + print( + f"{gif_name}: Candidate at step {i}: {best_f} Hz (~{maxline:.1f} sigma)" + ) axf.plot(f, mean_line, lw=1, c="k", zorder=10, label="mean", ls="-") @@ -703,7 +720,9 @@ def plot_transient_search(results, gif_name=None): if HAS_IMAGEIO: imageio.v3.imwrite(gif_name, all_images, duration=1000.0) else: - warnings.warn("imageio needed to save the transient search results " "into a gif image.") + warnings.warn( + "imageio needed to save the transient search results " "into a gif image." + ) return all_images @@ -803,7 +822,9 @@ def search_with_qffa_step( # dn = max(1, int(nbin / oversample)) linbinshifts = np.linspace(-nbin * npfact, nbin * npfact, int(oversample * npfact)) if search_fdot: - quabinshifts = np.linspace(-nbin * npfact, nbin * npfact, int(oversample * npfact)) + quabinshifts = np.linspace( + -nbin * npfact, nbin * npfact, int(oversample * npfact) + ) else: quabinshifts = np.array([0]) @@ -846,7 +867,7 @@ def search_with_qffa( f1 : float Maximum frequency to search - Other parameters + Other Parameters ---------------- nbin : int Number of bins to divide the profile into @@ -885,7 +906,9 @@ def search_with_qffa( maxerr = check_phase_error_after_casting_to_double(np.max(times), f1, fdot) if maxerr > 1 / nbin / 10: - warnings.warn(f"Maximum error on the phase expected when casting to " f"double: {maxerr}") + warnings.warn( + f"Maximum error on the phase expected when casting to " f"double: {maxerr}" + ) warnings.warn( "Casting to double produces non-negligible phase errors. " "Please use shorter light curves.", @@ -977,7 +1000,7 @@ def search_with_ffa(times, f0, f1, nbin=16, n=1, t0=None, t1=None): f1 : float Maximum frequency to search - Other parameters + Other Parameters ---------------- nbin : int Number of bins to divide the profile into @@ -1048,9 +1071,11 @@ def folding_search( fdotepsilon = 1e-2 * fdotstep trial_fdots = np.arange(fdotmin, fdotmax + fdotepsilon, fdotstep) if len(trial_fdots) > 1: - log.info("Searching {} frequencies and {} fdots".format(len(trial_freqs), len(trial_fdots))) + log.info( + f"Searching {len(trial_freqs)} frequencies and {len(trial_fdots)} fdots" + ) else: - log.info("Searching {} frequencies".format(len(trial_freqs))) + log.info(f"Searching {len(trial_freqs)} frequencies") results = func( times, @@ -1125,15 +1150,17 @@ def print_qffa_results(best_cand_table): if len(newtable[good]) == 0: print("No pulsations found. Best candidate and upper limit:") good = 0 - newtable["Pulsed amplitude (%)"] = [f"<{a:g} (90%)" for a in newtable["pulse_amp_ul_0.9"]] + newtable["Pulsed amplitude (%)"] = [ + f"<{a:g} (90%)" for a in newtable["pulse_amp_ul_0.9"] + ] else: print("Best candidate(s):") newtable["Pulsed amplitude (%)"] = [ - f"{a:g} ± {e:g}" for (a, e) in zip(newtable["pulse_amp"], newtable["pulse_amp_err"]) + f"{a:g} ± {e:g}" + for (a, e) in zip(newtable["pulse_amp"], newtable["pulse_amp_err"]) ] print(newtable["mjd", "f", "fdot", "fddot", "power", "Pulsed amplitude (%)"][good]) - return def get_xy_boundaries_from_level(x, y, image, level, x0, y0): @@ -1221,12 +1248,14 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): input_ef_periodogram : :class:`EFPeriodogram` Epoch folding periodogram object """ - if not hasattr(input_ef_periodogram, "M") or input_ef_periodogram.M is None: input_ef_periodogram.M = 1 ntrial = input_ef_periodogram.stat.size - if hasattr(input_ef_periodogram, "oversample") and input_ef_periodogram.oversample is not None: + if ( + hasattr(input_ef_periodogram, "oversample") + and input_ef_periodogram.oversample is not None + ): ntrial /= input_ef_periodogram.oversample ntrial = int(ntrial) if input_ef_periodogram.kind == "Z2n": @@ -1254,7 +1283,10 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): best_cands = find_peaks_in_image(input_ef_periodogram.stat, n=n_cands) fddot = 0 - if hasattr(input_ef_periodogram, "fddots") and input_ef_periodogram.fddots is not None: + if ( + hasattr(input_ef_periodogram, "fddots") + and input_ef_periodogram.fddots is not None + ): fddot = input_ef_periodogram.fddots best_cand_table = Table( @@ -1313,7 +1345,10 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): for i, idx in enumerate(best_cands): f_idx = fdot_idx = fddot_idx = 0 - if len(input_ef_periodogram.stat.shape) > 1 and input_ef_periodogram.stat.shape[0] > 1: + if ( + len(input_ef_periodogram.stat.shape) > 1 + and input_ef_periodogram.stat.shape[0] > 1 + ): f_idx, fdot_idx = idx allfreqs = input_ef_periodogram.freq[f_idx, :] allfdots = input_ef_periodogram.freq[:, fdot_idx] @@ -1324,7 +1359,9 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): input_ef_periodogram.fdots[f_idx, fdot_idx], ) max_stat = input_ef_periodogram.stat[f_idx, fdot_idx] - sig_e1_m, sig_e1 = power_confidence_limits(max_stat, c=0.68, n=input_ef_periodogram.N) + sig_e1_m, sig_e1 = power_confidence_limits( + max_stat, c=0.68, n=input_ef_periodogram.N + ) fmin, fmax, fdotmin, fdotmax = get_xy_boundaries_from_level( input_ef_periodogram.freq, input_ef_periodogram.fdots, @@ -1339,7 +1376,9 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): allstats_f = input_ef_periodogram.stat f = input_ef_periodogram.freq[f_idx] max_stat = input_ef_periodogram.stat[f_idx] - sig_e1_m, sig_e1 = power_confidence_limits(max_stat, c=0.68, n=input_ef_periodogram.N) + sig_e1_m, sig_e1 = power_confidence_limits( + max_stat, c=0.68, n=input_ef_periodogram.N + ) fmin, fmax = get_boundaries_from_level( input_ef_periodogram.freq, input_ef_periodogram.stat, sig_e1_m, f ) @@ -1352,7 +1391,9 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): if input_ef_periodogram.ncounts is None: continue - sig_0, sig_1 = power_confidence_limits(max_stat, c=0.90, n=input_ef_periodogram.N) + sig_0, sig_1 = power_confidence_limits( + max_stat, c=0.90, n=input_ef_periodogram.N + ) amp = amp_err = amp_ul = amp_1 = amp_0 = np.nan if max_stat < detlev: amp_ul = a_from_ssig(sig_1, input_ef_periodogram.ncounts) * 100 @@ -1401,7 +1442,8 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): if fname is not None: Table({"fdot": allfdots, "stat": allstats_fdot}).write( - f'{fname.replace(HEN_FILE_EXTENSION, "")}' f"_cand_{n_cands - i - 1}_f{f}.dat", + f'{fname.replace(HEN_FILE_EXTENSION, "")}' + f"_cand_{n_cands - i - 1}_f{f}.dat", overwrite=True, format="ascii", ) @@ -1539,7 +1581,8 @@ def _common_parser(args=None): "--step", default=None, type=float, - help="Step size of the frequency axis. Defaults to " "1/oversample/obs_length. ", + help="Step size of the frequency axis. Defaults to " + "1/oversample/obs_length. ", ) parser.add_argument( "--oversample", @@ -1569,7 +1612,8 @@ def _common_parser(args=None): ) parser.add_argument( "--transient", - help="Look for transient emission (produces an animated" " GIF with the dynamic Z search)", + help="Look for transient emission (produces an animated" + " GIF with the dynamic Z search)", default=False, action="store_true", ) @@ -1664,7 +1708,7 @@ def _common_main(args, func): kind_label = f"Z2{n}" ftype, events = get_file_type(fname) - out_fname = hen_root(fname) + "_{}".format(kind_label) + out_fname = hen_root(fname) + f"_{kind_label}" if args.emin is not None or args.emax is not None: emin = assign_value_if_none(args.emin, HENDRICS_STAR_VALUE) emax = assign_value_if_none(args.emax, HENDRICS_STAR_VALUE) @@ -1738,7 +1782,8 @@ def _common_main(args, func): if nbin / n < 8: nbin = n * 8 warnings.warn( - f"The number of bins is too small for Z search." f"Increasing to {nbin}" + f"The number of bins is too small for Z search." + f"Increasing to {nbin}" ) results = search_with_qffa( events.time, @@ -1760,7 +1805,9 @@ def _common_main(args, func): "The Fast Folding Algorithm functionality is experimental. Use" " with care, and feel free to report any issues." ) - results = search_with_ffa(events.time, args.fmin, args.fmax, nbin=args.nbin, n=n) + results = search_with_ffa( + events.time, args.fmin, args.fmax, nbin=args.nbin, n=n + ) ref_time = events.time[0] length = events.time.max() - events.time.min() @@ -1802,7 +1849,9 @@ def _common_main(args, func): pepoch=mjdref + ref_time / 86400, oversample=args.oversample, ) - efperiodogram.upperlim = pf_upper_limit(np.max(stats), events.time.size, n=args.N) + efperiodogram.upperlim = pf_upper_limit( + np.max(stats), events.time.size, n=args.N + ) efperiodogram.ncounts = events.time.size best_peaks = None if args.find_candidates: @@ -1849,14 +1898,12 @@ def _common_main(args, func): def main_efsearch(args=None): """Main function called by the `HENefsearch` command line script.""" - with log.log_to_file("HENefsearch.log"): return _common_main(args, epoch_folding_search) def main_zsearch(args=None): """Main function called by the `HENzsearch` command line script.""" - with log.log_to_file("HENzsearch.log"): return _common_main(args, z_n_search) @@ -1911,7 +1958,9 @@ def main_z2vspf(args=None): type=int, help="Number of trial values for the pulsed fraction", ) - parser.add_argument("--outfile", default=None, type=str, help="Output table file name") + parser.add_argument( + "--outfile", default=None, type=str, help="Output table file name" + ) parser.add_argument( "--show-z-values", nargs="+", @@ -1951,14 +2000,16 @@ def main_z2vspf(args=None): if args.emin is not None or args.emax is not None: events, elabel = filter_energy(events, args.emin, args.emax) - result_table = z2_vs_pf(events, deadtime=0.0, ntrials=args.ntrial, outfile=outfile, N=args.N) + result_table = z2_vs_pf( + events, deadtime=0.0, ntrials=args.ntrial, outfile=outfile, N=args.N + ) if HAS_MPL: fig = plt.figure("Results", figsize=(10, 6)) plt.scatter(result_table["pf"] * 100, result_table["z2"]) plt.semilogy() plt.grid(True) plt.xlabel(r"Pulsed fraction (%)") - plt.ylabel(r"$Z^2_{}$".format(args.N)) + plt.ylabel(rf"$Z^2_{args.N}$") # plt.show() if args.show_z_values is not None: for z in args.show_z_values: @@ -2005,7 +2056,9 @@ def main_accelsearch(args=None): type=float, help="Maximum frequency to search, in Hz", ) - parser.add_argument("--nproc", default=1, type=int, help="Number of processors to use") + parser.add_argument( + "--nproc", default=1, type=int, help="Number of processors to use" + ) parser.add_argument( "--zmax", default=100, @@ -2110,7 +2163,9 @@ def main_accelsearch(args=None): t0 = GTI[0, 0] Nbins = int(np.rint(max_length / dt)) if Nbins > 10**8: - log.info(f"The number of bins is more than 100 millions: {Nbins}. " "Using memmap.") + log.info( + f"The number of bins is more than 100 millions: {Nbins}. " "Using memmap." + ) dt = adjust_dt_for_power_of_two(dt, max_length) diff --git a/hendrics/exposure.py b/hendrics/exposure.py index 45f837b9..3200b186 100644 --- a/hendrics/exposure.py +++ b/hendrics/exposure.py @@ -6,13 +6,16 @@ """ import warnings -from stingray.lightcurve import Lightcurve -from stingray.gti import create_gti_mask -from astropy import log + import numpy as np +from stingray.gti import create_gti_mask from stingray.io import load_events_and_gtis -from .io import get_file_type, save_lcurve, HEN_FILE_EXTENSION, load_data -from .base import hen_root, _assign_value_if_none +from stingray.lightcurve import Lightcurve + +from astropy import log + +from .base import _assign_value_if_none, hen_root +from .io import HEN_FILE_EXTENSION, get_file_type, save_lcurve def get_livetime_per_bin(times, events, priors, dt=None, gti=None): @@ -43,7 +46,9 @@ def get_livetime_per_bin(times, events, priors, dt=None, gti=None): [[time[0] - dt[0]/2, time[-1] + dt[-1]/2]] """ - assert len(events) == len(priors), "`events` and `priors` must be of the same length" + assert len(events) == len( + priors + ), "`events` and `priors` must be of the same length" dt = _assign_value_if_none(dt, np.median(np.diff(times))) @@ -117,14 +122,14 @@ def get_livetime_per_bin(times, events, priors, dt=None, gti=None): livetime_array[ev_bin_good] += ev_good - _tbins assert np.all( ev_good - _tbins >= 0 - ), "Invalid boundaries. Contact the developer: {}".format(ev_good - _tbins) + ), f"Invalid boundaries. Contact the developer: {ev_good - _tbins}" l_idx = np.searchsorted(tbin_starts, lt_good, "right") _tbins = tbin_starts[l_idx] livetime_array[lts_bin_good] += _tbins - lt_good assert np.all( _tbins - lt_good >= 0 - ), "Invalid boundaries. Contact the developer: {}".format(_tbins - lt_good) + ), f"Invalid boundaries. Contact the developer: {_tbins - lt_good}" # Complete bins if bin_diff > 1: @@ -172,9 +177,15 @@ def _plot_dead_time_from_uf(uf_file, outroot="expo"): bins = np.percentile(dead_times, np.linspace(0, 100, 1000)) hist_all, bins_all = histogram(dead_times, bins=bins, density=True) - hist_shield, bins_shield = histogram(dead_times[shields > 0], bins=bins, density=True) - hist_noshield, bins_noshield = histogram(dead_times[shields == 0], bins=bins, density=True) - hist_shld_hi, bins_shld_hi = histogram(dead_times[shld_hi > 0], bins=bins, density=True) + hist_shield, bins_shield = histogram( + dead_times[shields > 0], bins=bins, density=True + ) + hist_noshield, bins_noshield = histogram( + dead_times[shields == 0], bins=bins, density=True + ) + hist_shld_hi, bins_shld_hi = histogram( + dead_times[shld_hi > 0], bins=bins, density=True + ) bin_centers = bins[:-1] + np.diff(bins) / 2 fig = plt.figure("Dead time distribution", figsize=(10, 10)) @@ -195,7 +206,7 @@ def _plot_dead_time_from_uf(uf_file, outroot="expo"): bin_centers, hs, drawstyle="steps-mid", - label="shield time {}".format(sht), + label=f"shield time {sht}", ) ax2.set_xlabel("Dead time (s)") ax2.set_ylabel("Occurrences (arbitrary units)") @@ -291,7 +302,9 @@ def correct_lightcurve(lc_file, uf_file, outname=None, expo_limit=1e-7): outname : str Output file name """ - outname = _assign_value_if_none(outname, hen_root(lc_file) + "_lccorr" + HEN_FILE_EXTENSION) + outname = _assign_value_if_none( + outname, hen_root(lc_file) + "_lccorr" + HEN_FILE_EXTENSION + ) ftype, contents = get_file_type(lc_file) @@ -327,6 +340,7 @@ def correct_lightcurve(lc_file, uf_file, outname=None, expo_limit=1e-7): def main(args=None): """Main function called by the `HENexposure` command line script.""" import argparse + from .base import _add_default_args, check_negative_numbers_in_args description = "Create exposure light curve based on unfiltered event files." @@ -341,7 +355,9 @@ def main(args=None): default=None, help="Root of output file names", ) - parser.add_argument("--plot", help="Plot on window", default=False, action="store_true") + parser.add_argument( + "--plot", help="Plot on window", default=False, action="store_true" + ) _add_default_args(parser, ["loglevel", "debug"]) args = check_negative_numbers_in_args(args) @@ -373,7 +389,6 @@ def main(args=None): _plot_dead_time_from_uf(uf_file, outroot) except Exception as e: warnings.warn(str(e)) - pass if args.plot: import matplotlib.pyplot as plt diff --git a/hendrics/exvar.py b/hendrics/exvar.py index 0fe5e2f1..cd582ac4 100644 --- a/hendrics/exvar.py +++ b/hendrics/exvar.py @@ -1,16 +1,16 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- """ Created on Thu Aug 17 08:55:47 2017 @author: marta """ -from astropy import log from stingray.utils import excess_variance -from .io import load_lcurve -from .io import save_as_qdp + +from astropy import log + from .base import hen_root +from .io import load_lcurve, save_as_qdp def fvar(lc): @@ -27,6 +27,7 @@ def excvar_norm(lc): def main(args=None): import argparse + from .base import _add_default_args, check_negative_numbers_in_args description = "Calculate excess variance in light curve chunks" diff --git a/hendrics/fake.py b/hendrics/fake.py index 7a8057e7..03e27558 100644 --- a/hendrics/fake.py +++ b/hendrics/fake.py @@ -1,25 +1,24 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """Functions to simulate data and produce a fake event file.""" -import os -import warnings import copy +import os + import numpy as np import numpy.random as ra -from astropy import log -from astropy.io.fits import Header -from astropy.logger import AstropyUserWarning from stingray.events import EventList +from stingray.filters import filter_for_deadtime +from stingray.io import get_key_from_mission_info, read_mission_info from stingray.lightcurve import Lightcurve from stingray.utils import assign_value_if_none -from stingray.filters import filter_for_deadtime -from stingray.io import read_mission_info, get_key_from_mission_info -from .io import load_lcurve -from .io import load_events, save_events, HEN_FILE_EXTENSION -from .base import _empty, get_file_format, r_in + +from astropy import log +from astropy.io.fits import Header + +from .base import deorbit_events, get_file_format, r_in from .fold import filter_energy +from .io import HEN_FILE_EXTENSION, load_events, load_lcurve, save_events from .lcurve import lcurve_from_fits -from .base import njit, deorbit_events def _clean_up_header(header): @@ -67,7 +66,9 @@ def _fill_in_default_information(tbheader): False, "TRUE if timestamps corrected by gnd sware", ) - tbheader["COMMENT"] = "MJDREFI+MJDREFF = epoch of Jan 1, 2010, in TT " "time system." + tbheader["COMMENT"] = ( + "MJDREFI+MJDREFF = epoch of Jan 1, 2010, in TT " "time system." + ) tbheader["TIMEUNIT"] = ("s", "unit for time keywords") return tbheader @@ -119,7 +120,6 @@ def generate_fake_fits_observation( Total livetime. Default is tstop - tstart """ from astropy.io import fits - import numpy.random as ra inheader = None if event_list is None: @@ -133,7 +133,9 @@ def generate_fake_fits_observation( inheader = _clean_up_header(inheader) ev_list = event_list.time - gti = assign_value_if_none(event_list.gti, np.asarray([[ev_list[0], ev_list[-1]]])) + gti = assign_value_if_none( + event_list.gti, np.asarray([[ev_list[0], ev_list[-1]]]) + ) mission = assign_value_if_none(mission, event_list.mission) instr = assign_value_if_none(instr, event_list.instr) tstart = assign_value_if_none(tstart, gti[0, 0]) @@ -305,7 +307,9 @@ def _read_light_curve(filename): return lc -def acceptance_rejection(dt, counts_per_bin, t0=0.0, poissonize_n_events=False, deadtime=0.0): +def acceptance_rejection( + dt, counts_per_bin, t0=0.0, poissonize_n_events=False, deadtime=0.0 +): """ Examples -------- @@ -393,7 +397,7 @@ def scramble( event_list: :class:`stingray.events.Eventlist` object Input event list - Other parameters + Other Parameters ---------------- smooth_kind: str in ['flat', 'smooth', 'pulsed'] if 'flat', count the events GTI by GTI without caring about long-term @@ -518,10 +522,12 @@ def scramble( def main_scramble(args=None): """Main function called by the `HENscramble` command line script.""" import argparse + from .base import _add_default_args, check_negative_numbers_in_args description = ( - "Scramble the events inside an event list, maintaining the same " "energies and GTIs" + "Scramble the events inside an event list, maintaining the same " + "energies and GTIs" ) parser = argparse.ArgumentParser(description=description) @@ -582,7 +588,9 @@ def main_scramble(args=None): emin, emax = args.energy_interval event_list, elabel = filter_energy(event_list, emin, emax) if elabel != "Energy": - raise ValueError("You are filtering by energy but the data are not calibrated") + raise ValueError( + "You are filtering by energy but the data are not calibrated" + ) new_event_list = scramble( event_list, @@ -608,7 +616,9 @@ def main_scramble(args=None): if args.energy_interval is not None: label += f"_{emin:g}-{emax:g}keV" - outfile = args.fname.replace(HEN_FILE_EXTENSION, f"{label}" + HEN_FILE_EXTENSION) + outfile = args.fname.replace( + HEN_FILE_EXTENSION, f"{label}" + HEN_FILE_EXTENSION + ) save_events(new_event_list, outfile) return outfile @@ -616,6 +626,7 @@ def main_scramble(args=None): def main(args=None): """Main function called by the `HENfake` command line script.""" import argparse + from .base import _add_default_args, check_negative_numbers_in_args description = ( @@ -653,7 +664,9 @@ def main(args=None): default="events.evt", help="Output file name", ) - parser.add_argument("-i", "--instrument", type=str, default=None, help="Instrument name") + parser.add_argument( + "-i", "--instrument", type=str, default=None, help="Instrument name" + ) parser.add_argument("-m", "--mission", type=str, default=None, help="Mission name") parser.add_argument( "--tstart", @@ -706,12 +719,14 @@ def main(args=None): tstop = assign_value_if_none(args.tstop, 1024) dt = (tstop - tstart) / 1024 t = np.arange(tstart, tstop + 1, dt) - lc = Lightcurve(time=t, counts=args.ctrate * dt + np.zeros_like(t), dt=dt) + lc = Lightcurve( + time=t, counts=args.ctrate * dt + np.zeros_like(t), dt=dt + ) event_list.simulate_times(lc) nevents = len(event_list.time) event_list.pi = np.zeros(nevents, dtype=int) event_list.mjdref = args.mjdref - log.info("{} events generated".format(nevents)) + log.info(f"{nevents} events generated") else: event_list = None @@ -724,7 +739,7 @@ def main(args=None): event_list, deadtime, dt_sigma=deadtime_sigma, return_all=True ) - log.info("{} events after filter".format(len(event_list.time))) + log.info(f"{len(event_list.time)} events after filter") prior = np.zeros_like(event_list.time) diff --git a/hendrics/ffa.py b/hendrics/ffa.py index e8a1c232..44cc8dcd 100644 --- a/hendrics/ffa.py +++ b/hendrics/ffa.py @@ -1,8 +1,8 @@ import functools + import numpy as np -from .base import njit, vectorize, float32, float64, int32, int64 -from .base import show_progress +from .base import float32, float64, int32, int64, njit, show_progress, vectorize """ prof_n step0 step1 step2 @@ -88,7 +88,6 @@ def _z_n_fast_cached(norm, cached_sin, cached_cos, n=2): >>> assert np.isclose(_z_n_fast_cached(norm, cached_sin, cached_cos, n=4), 50) >>> assert np.isclose(_z_n_fast_cached(norm, cached_sin, cached_cos, n=2), 50) """ - total_norm = np.sum(norm) result = 0 @@ -129,7 +128,6 @@ def z_n_fast_cached(norm, n=2): >>> assert np.isclose(z_n_fast_cached(norm, n=4), 50) >>> assert np.isclose(z_n_fast_cached(norm, n=2), 50) """ - cached_sin = cached_sin_harmonics(norm.size, n) cached_cos = cached_cos_harmonics(norm.size, n) @@ -139,7 +137,6 @@ def z_n_fast_cached(norm, n=2): @njit() def _z_n_fast_cached_all(norm, cached_sin, cached_cos, ks): """Numba-compiled core of z_n_fast_cached_all""" - total_norm = np.sum(norm) all_zs = np.zeros(ks.size) @@ -186,7 +183,6 @@ def z_n_fast_cached_all(norm, nmax=20): >>> assert np.isclose(allzs[1], 50) >>> assert np.isclose(allzs[3], 50) """ - cached_sin = cached_sin_harmonics(norm.size, nmax) cached_cos = cached_cos_harmonics(norm.size, nmax) ks = np.arange(1, nmax + 1, dtype=int) @@ -255,7 +251,6 @@ def start_value(prof_n, step): >>> assert start_value(7, 1) == 5 >>> assert start_value(10, 2) == 9 """ - n = prof_n val = 0 @@ -304,7 +299,9 @@ def ffa_step(array, step, ntables): array_reshaped_dum[prof_n, :] = sum_arrays(array[start, :], rolled[:]) else: - array_reshaped_dum[prof_n, :] = sum_arrays(array[start, :], array[jumpstart, :]) + array_reshaped_dum[prof_n, :] = sum_arrays( + array[start, :], array[jumpstart, :] + ) return array_reshaped_dum @@ -314,7 +311,7 @@ def _ffa(array_reshaped, bin_period, ntables, z_n_n=2): """Fast folding algorithm search.""" periods = np.array([bin_period + n / (ntables - 1) for n in range(ntables)]) - for step in range(0, int(np.log2(ntables))): + for step in range(int(np.log2(ntables))): array_reshaped = ffa_step(array_reshaped, step, ntables) twopiphases = np.pi * 2 * np.arange(0, 1, 1 / array_reshaped.shape[1]) @@ -328,7 +325,9 @@ def _ffa(array_reshaped, bin_period, ntables, z_n_n=2): stats = np.zeros(ntables) for i in range(array_reshaped.shape[0]): - stats[i] = _z_n_fast_cached(array_reshaped[i, :], cached_cos, cached_sin, n=z_n_n) + stats[i] = _z_n_fast_cached( + array_reshaped[i, :], cached_cos, cached_sin, n=z_n_n + ) return periods, stats @@ -358,7 +357,9 @@ def _quick_rebin(counts, current_rebin): >>> assert np.allclose(reb, [3, 7, 11, 15, 19]) """ n = int(counts.size // current_rebin) - rebinned_counts = np.sum(counts[: n * current_rebin].reshape(n, current_rebin), axis=1) + rebinned_counts = np.sum( + counts[: n * current_rebin].reshape(n, current_rebin), axis=1 + ) return rebinned_counts diff --git a/hendrics/fold.py b/hendrics/fold.py index 071f9f6c..929b7d0b 100644 --- a/hendrics/fold.py +++ b/hendrics/fold.py @@ -1,25 +1,22 @@ """Interactive phaseogram.""" -import warnings -import copy import argparse -import numpy as np +import copy import urllib -from scipy.signal import savgol_filter -from scipy.interpolate import interp1d +import warnings + +import numpy as np from scipy import optimize -from astropy.stats import poisson_conf_interval -from astropy import log -from stingray.pulse.pulsar import fold_events, pulse_phase, get_TOA -from stingray.pulse.pulsar import pulse_phase, htest +from scipy.interpolate import interp1d +from scipy.signal import savgol_filter +from stingray.pulse.pulsar import fold_events, htest, pulse_phase from stingray.utils import assign_value_if_none, fft, fftfreq, ifft -from stingray.events import EventList - -from hendrics.ml_timing import get_template_func +from astropy import log +from astropy.stats import poisson_conf_interval from .base import hen_root, normalize_dyn_profile -from .io import load_events, filter_energy +from .io import filter_energy, load_events try: from tqdm import tqdm as show_progress @@ -35,7 +32,9 @@ def show_progress(a): # import pint HAS_PINT = True except (ImportError, urllib.error.URLError): - warnings.warn("PINT is not installed. " "Some pulsar functionality will not be available") + warnings.warn( + "PINT is not installed. " "Some pulsar functionality will not be available" + ) HAS_PINT = False from .base import deorbit_events @@ -109,7 +108,9 @@ def create_template_from_profile_sins( return template, additional_phase -def create_template_from_profile(phase, profile, profile_err, imagefile="template.png", norm=1): +def create_template_from_profile( + phase, profile, profile_err, imagefile="template.png", norm=1 +): """ Parameters ---------- @@ -136,8 +137,8 @@ def create_template_from_profile(phase, profile, profile_err, imagefile="templat ... >>> assert np.allclose(template, profile, atol=0.001) """ - from scipy.interpolate import splrep, splev import matplotlib.pyplot as plt + from scipy.interpolate import splev, splrep ph = np.concatenate((phase - 1, phase, phase + 1)) prof = np.concatenate((profile, profile, profile)) @@ -306,7 +307,7 @@ def get_TOAs_from_events(events, folding_length, *frequency_derivatives, **kwarg *frequency_derivatives : floats pulse frequency, first derivative, second derivative, etc. - Other parameters + Other Parameters ---------------- pepoch : float, default None Epoch of timing solution, in the same units as ev_times. If none, the @@ -418,7 +419,9 @@ def get_TOAs_from_events(events, folding_length, *frequency_derivatives, **kwarg from .ml_timing import ml_pulsefit - pars, errs = ml_pulsefit(profile, template, calculate_errors=True, fit_base=fit_base) + pars, errs = ml_pulsefit( + profile, template, calculate_errors=True, fit_base=fit_base + ) if np.any(np.isnan(pars)) or pars[0] == 0.0 or np.any(np.isnan(errs)): warnings.warn( @@ -446,7 +449,9 @@ def get_TOAs_from_events(events, folding_length, *frequency_derivatives, **kwarg factor = np.std(phs) / np.mean(phs_errs) if phs.size > 15: - log.info("Correcting TOA errors for the real scatter. Don't trust them literally") + log.info( + "Correcting TOA errors for the real scatter. Don't trust them literally" + ) # print(phs, phs_errs, factor) toa_errs = toa_errs * factor @@ -486,13 +491,14 @@ def dbl_cos_fit_func(p, x): base = p[0] startidx = 1 first_harm = p[startidx] * np.cos(2 * np.pi * x + 2 * np.pi * p[startidx + 1]) - second_harm = p[startidx + 2] * np.cos(4.0 * np.pi * x + 4 * np.pi * p[startidx + 3]) + second_harm = p[startidx + 2] * np.cos( + 4.0 * np.pi * x + 4 * np.pi * p[startidx + 3] + ) return base + first_harm + second_harm def std_fold_fit_func(p, x): """Chooses the fit function used in the fit.""" - return dbl_cos_fit_func(p, x) @@ -523,7 +529,9 @@ def adjust_amp_phase(pars): return pars -def fit_profile_with_sinusoids(profile, profile_err, debug=False, nperiods=1, baseline=False): +def fit_profile_with_sinusoids( + profile, profile_err, debug=False, nperiods=1, baseline=False +): """ Fit a folded profile with the std_fold_fit_func. @@ -537,7 +545,7 @@ def fit_profile_with_sinusoids(profile, profile_err, debug=False, nperiods=1, ba profile_err : array of floats the error on the folded profile elements - Other parameters + Other Parameters ---------------- debug : bool, optional print debug info @@ -582,16 +590,20 @@ def fit_profile_with_sinusoids(profile, profile_err, debug=False, nperiods=1, ba if debug: log.debug(guess_pars) plt.plot(x, std_fold_fit_func(guess_pars, x), "r--") - fit_pars, success = optimize.leastsq(std_residuals, guess_pars[:], args=(x, profile)) + fit_pars, success = optimize.leastsq( + std_residuals, guess_pars[:], args=(x, profile) + ) if debug: plt.plot(x, std_fold_fit_func(fit_pars, x), "g--") - fit_pars[startidx : startidx + 2] = adjust_amp_phase(fit_pars[startidx : startidx + 2]) + fit_pars[startidx : startidx + 2] = adjust_amp_phase( + fit_pars[startidx : startidx + 2] + ) fit_pars[startidx + 2 : startidx + 4] = adjust_amp_phase( fit_pars[startidx + 2 : startidx + 4] ) - chisq = np.sum((profile - std_fold_fit_func(fit_pars, x)) ** 2 / profile_err**2) / ( - len(profile) - (startidx + 4) - ) + chisq = np.sum( + (profile - std_fold_fit_func(fit_pars, x)) ** 2 / profile_err**2 + ) / (len(profile) - (startidx + 4)) if debug: plt.plot(x, std_fold_fit_func(fit_pars, x), "b--") if chisq < chisq_save: @@ -641,8 +653,8 @@ def run_folding( colormap="cubehelix", **opts, ): - from matplotlib.gridspec import GridSpec import matplotlib.pyplot as plt + from matplotlib.gridspec import GridSpec file_label = "" ev = load_events(file) @@ -680,7 +692,9 @@ def run_folding( smooth_window = np.min([len(profile), 10]) smooth_window = _check_odd(smooth_window) - smoothed_profile = savgol_filter(profile, window_length=smooth_window, polyorder=3, mode="wrap") + smoothed_profile = savgol_filter( + profile, window_length=smooth_window, polyorder=3, mode="wrap" + ) profile = np.concatenate((profile, profile)) smooth = np.concatenate((smoothed_profile, smoothed_profile)) @@ -688,7 +702,9 @@ def run_folding( if plot_energy: histen, _ = np.histogram(energy, bins=biny) - hist2d, _, _ = np.histogram2d(phases.astype(np.float64), energy, bins=(binx, biny)) + hist2d, _, _ = np.histogram2d( + phases.astype(np.float64), energy, bins=(binx, biny) + ) binx = np.concatenate((binx[:-1], binx + 1)) meanbins = (binx[:-1] + binx[1:]) / 2 @@ -725,11 +741,13 @@ def run_folding( meanbins, smooth, drawstyle="steps-mid", - label="Smooth profile " "(P.F. = {:.1f}%)".format(100 * (max - min) / max), + label="Smooth profile " f"(P.F. = {100 * (max - min) / max:.1f}%)", color="k", zorder=3, ) - err_low, err_high = poisson_conf_interval(smooth, interval="frequentist-confidence", sigma=3) + err_low, err_high = poisson_conf_interval( + smooth, interval="frequentist-confidence", sigma=3 + ) try: ax0.fill_between( @@ -777,7 +795,9 @@ def run_folding( errs = [] meannrgs = (biny[:-1] + biny[1:]) / 2 for i, prof in enumerate(hist2d_save.T): - smooth = savgol_filter(prof, window_length=smooth_window, polyorder=3, mode="wrap") + smooth = savgol_filter( + prof, window_length=smooth_window, polyorder=3, mode="wrap" + ) mean = np.mean(smooth) shift = 3 * np.sqrt(mean) max = np.max(smooth) @@ -793,7 +813,7 @@ def run_folding( ax2.plot( meanbins, smooth - mean + i * shift, - label="{}={:.2f}-{:.2f}".format(elabel, biny[i], biny[i + 1]), + label=f"{elabel}={biny[i]:.2f}-{biny[i + 1]:.2f}", ) std = np.std(prof - smooth) pfs.append(pf) @@ -840,8 +860,12 @@ def main_fold(args=None): help="Initial frequency to fold", default=None, ) - parser.add_argument("--fdot", type=float, required=False, help="Initial fdot", default=0) - parser.add_argument("--fddot", type=float, required=False, help="Initial fddot", default=0) + parser.add_argument( + "--fdot", type=float, required=False, help="Initial fdot", default=0 + ) + parser.add_argument( + "--fddot", type=float, required=False, help="Initial fddot", default=0 + ) parser.add_argument( "--tref", type=float, @@ -927,7 +951,8 @@ def main_fold(args=None): def main_deorbit(args=None): import argparse - from .base import hen_root, _add_default_args + + from .base import _add_default_args, hen_root from .io import HEN_FILE_EXTENSION, load_events, save_events description = "Deorbit the event arrival times" diff --git a/hendrics/fspec.py b/hendrics/fspec.py index 58c16342..18bd9df9 100644 --- a/hendrics/fspec.py +++ b/hendrics/fspec.py @@ -1,33 +1,34 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """Functions to calculate frequency spectra.""" -import copy -import warnings import contextlib +import copy import os -from stingray.gti import cross_gtis +import warnings + +import numpy as np from stingray.crossspectrum import AveragedCrossspectrum +from stingray.gti import cross_gtis, time_intervals_from_gtis +from stingray.lombscargle import LombScargleCrossspectrum, LombScarglePowerspectrum from stingray.powerspectrum import AveragedPowerspectrum from stingray.utils import show_progress -from stingray.utils import assign_value_if_none -from stingray.gti import time_intervals_from_gtis -from stingray.events import EventList -import numpy as np from astropy import log from astropy.logger import AstropyUserWarning + from .base import ( - hen_root, + HENDRICS_STAR_VALUE, common_name, - _assign_value_if_none, + hen_root, interpret_bintime, - HENDRICS_STAR_VALUE, ) -from stingray.lombscargle import LombScargleCrossspectrum, LombScarglePowerspectrum - -from .io import sort_files, save_pds, load_data -from .io import HEN_FILE_EXTENSION, get_file_type -from .io import filter_energy +from .io import ( + HEN_FILE_EXTENSION, + filter_energy, + get_file_type, + save_pds, + sort_files, +) def average_periodograms(fspec_iterable, total=None): @@ -48,7 +49,6 @@ def average_periodograms(fspec_iterable, total=None): >>> assert np.allclose(tot_pds.power_err, pds.power_err / np.sqrt(3)) >>> assert tot_pds.m == 3 """ - all_spec = [] for i, contents in enumerate(show_progress(fspec_iterable, total=total)): freq = contents.freq @@ -176,7 +176,9 @@ def _provide_periodograms(events, fftlen, dt, norm): for new_ev in _distribute_events(events, fftlen): # Hack: epsilon slightly below zero, to allow for a GTI to be recognized as such new_ev.gti[:, 1] += dt / 10 - pds = AveragedPowerspectrum(new_ev, dt=dt, segment_size=fftlen, norm=norm, silent=True) + pds = AveragedPowerspectrum( + new_ev, dt=dt, segment_size=fftlen, norm=norm, silent=True + ) pds.fftlen = fftlen yield pds @@ -411,7 +413,9 @@ def calc_cpds( "series (e.g. both events or both light curves)" ) - if (emin is not None or emax is not None) and (ftype1 != "events" or ftype2 != "events"): + if (emin is not None or emax is not None) and ( + ftype1 != "events" or ftype2 != "events" + ): warnings.warn("Energy selection only makes sense for event lists") if ftype1 == "events": lc1, _ = filter_energy(lc1, emin, emax) @@ -551,7 +555,6 @@ def calc_fspec( [5] Miyamoto et al. 1991, ApJ, 383, 784 """ - log.info("Using %s normalization" % normalization) log.info("Using %s processors" % nproc) @@ -693,7 +696,9 @@ def dumpdyn_main(args=None): help=("List of files in any valid HENDRICS " "format for PDS or CPDS"), nargs="+", ) - parser.add_argument("--noplot", help="plot results", default=False, action="store_true") + parser.add_argument( + "--noplot", help="plot results", default=False, action="store_true" + ) args = parser.parse_args(args) @@ -706,6 +711,7 @@ def dumpdyn_main(args=None): def main(args=None): """Main function called by the `HENfspec` command line script.""" import argparse + from .base import _add_default_args, check_negative_numbers_in_args description = ( @@ -752,7 +758,9 @@ def main(args=None): "--norm", type=str, default="leahy", - help="Normalization to use" + " (Accepted: leahy and rms;" + ' Default: "leahy")', + help="Normalization to use" + + " (Accepted: leahy and rms;" + + ' Default: "leahy")', ) parser.add_argument( "--noclobber", diff --git a/hendrics/io.py b/hendrics/io.py index 204aa2af..1a155c8b 100644 --- a/hendrics/io.py +++ b/hendrics/io.py @@ -1,26 +1,25 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """Functions to perform input/output operations.""" -import sys -import shutil -import os -import glob import copy -import re -from typing import Tuple -import logging - -from collections.abc import Iterable +import glob import importlib -import warnings -import pickle +import logging +import os import os.path -import numpy as np -from astropy.table import Table +import pickle +import shutil +import sys +import warnings +from collections.abc import Iterable +from typing import Tuple -from hendrics.base import get_file_extension, get_file_format, splitext_improved +import numpy as np from stingray.base import StingrayObject, StingrayTimeseries +from astropy.table import Table +from hendrics.base import get_file_format, splitext_improved + try: import h5py @@ -38,21 +37,19 @@ warnings.warn(msg) HEN_FILE_EXTENSION = ".p" HAS_NETCDF = False - pass -from astropy.modeling.core import Model -from astropy import log -from astropy.logger import AstropyUserWarning -from astropy.io import fits -from stingray.utils import assign_value_if_none +from stingray.crossspectrum import AveragedCrossspectrum, Crossspectrum from stingray.events import EventList from stingray.lightcurve import Lightcurve -from stingray.powerspectrum import Powerspectrum, AveragedPowerspectrum -from stingray.crossspectrum import Crossspectrum, AveragedCrossspectrum +from stingray.powerspectrum import AveragedPowerspectrum, Powerspectrum from stingray.pulse.modeling import SincSquareModel from stingray.pulse.search import search_best_peaks +from stingray.utils import assign_value_if_none + +from astropy import log +from astropy.logger import AstropyUserWarning +from astropy.modeling.core import Model -from .base import _order_list_of_arrays, _empty, is_string, force_iterable -from .base import find_peaks_in_image, hen_root +from .base import find_peaks_in_image, hen_root, is_string try: _ = np.complex256 @@ -60,12 +57,12 @@ except Exception: HAS_C256 = False -cpl128 = np.dtype([(str("real"), np.double), (str("imag"), np.double)]) +cpl128 = np.dtype([("real", np.double), ("imag", np.double)]) if HAS_C256: - cpl256 = np.dtype([(str("real"), np.longdouble), (str("imag"), np.longdouble)]) + cpl256 = np.dtype([("real", np.longdouble), ("imag", np.longdouble)]) -class EFPeriodogram(object): +class EFPeriodogram: def __init__( self, freq=None, @@ -113,7 +110,7 @@ def __init__( self.ncounts = ncounts def find_peaks(self, conflevel=99.0): - from .base import z2_n_detection_level, fold_detection_level + from .base import fold_detection_level, z2_n_detection_level ntrial = self.stat.size if hasattr(self, "oversample") and self.oversample is not None: @@ -129,7 +126,9 @@ def find_peaks(self, conflevel=99.0): n_summed_spectra=int(self.M), ) else: - threshold = fold_detection_level(nbin=int(self.nbin), epsilon=epsilon, ntrial=ntrial) + threshold = fold_detection_level( + nbin=int(self.nbin), epsilon=epsilon, ntrial=ntrial + ) if len(self.stat.shape) == 1: best_peaks, best_stat = search_best_peaks(self.freq, self.stat, threshold) @@ -206,7 +205,10 @@ def filter_energy(ev: EventList, emin: float, emax: float) -> Tuple[EventList, s # For some reason the doctest doesn't work if I don't do this instead # of using warnings.warn if elabel == "": - log.error("No Energy or PI information available. " "No energy filter applied to events") + log.error( + "No Energy or PI information available. " + "No energy filter applied to events" + ) return ev, "" if emax is None and emin is None: @@ -405,15 +407,15 @@ def read_from_netcdf(fname): # Handle special case of complex if dum.dtype == cpl128: arr = np.empty(values.shape, dtype=np.complex128) - arr.real = values[str("real")] - arr.imag = values[str("imag")] + arr.real = values["real"] + arr.imag = values["imag"] values = arr # Handle special case of complex if HAS_C256 and dum.dtype == cpl256: arr = np.empty(values.shape, dtype=np.complex256) - arr.real = values[str("real")] - arr.imag = values[str("imag")] + arr.real = values["real"] + arr.imag = values["imag"] values = arr if dum.dtype == str or dum.size == 1: @@ -500,7 +502,9 @@ def get_file_type(fname, raw_data=False): if "Lightcurve" in ftype_raw: ftype = "lc" fun = load_lcurve - elif ("Powercolor" in ftype_raw) or ("StingrayTimeseries" in ftype_raw and "hue" in contents): + elif ("Powercolor" in ftype_raw) or ( + "StingrayTimeseries" in ftype_raw and "hue" in contents + ): ftype = "powercolor" fun = load_timeseries elif "StingrayTimeseries" in ftype_raw or "Color" in ftype_raw: @@ -614,7 +618,6 @@ def save_lcurve(lcurve, fname, lctype="Lightcurve"): fname: str Name of output file """ - fmt = get_file_format(fname) if hasattr(lcurve, "_mask") and lcurve._mask is not None and np.any(~lcurve._mask): @@ -664,13 +667,12 @@ def load_lcurve(fname): # ---- Functions to save epoch folding results def save_folding(efperiodogram, fname): """Save PDS in a file.""" - outdata = copy.copy(efperiodogram.__dict__) outdata["__sr__class__type__"] = "EFPeriodogram" if "best_fits" in outdata and efperiodogram.best_fits is not None: model_files = [] for i, b in enumerate(efperiodogram.best_fits): - mfile = fname.replace(HEN_FILE_EXTENSION, "__mod{}__.p".format(i)) + mfile = fname.replace(HEN_FILE_EXTENSION, f"__mod{i}__.p") save_model(b, mfile) model_files.append(mfile) outdata.pop("best_fits") @@ -707,7 +709,9 @@ def load_folding(fname): # ---- Functions to save PDSs -def save_pds(cpds, fname, save_all=False, save_dyn=False, no_auxil=False, save_lcs=False): +def save_pds( + cpds, fname, save_all=False, save_dyn=False, no_auxil=False, save_lcs=False +): """Save PDS in a file.""" from .base import mkdir_p @@ -754,7 +758,9 @@ def save_pds(cpds, fname, save_all=False, save_dyn=False, no_auxil=False, save_l lc = getattr(cpds, lcattr) if isinstance(lc, Iterable): if len(lc) > 1: - warnings.warn("Saving multiple light curves is not supported. Saving only one") + warnings.warn( + "Saving multiple light curves is not supported. Saving only one" + ) lc = lc[0] if isinstance(lc, Lightcurve): save_lcurve(lc, lc_name) @@ -794,7 +800,7 @@ def save_pds(cpds, fname, save_all=False, save_dyn=False, no_auxil=False, save_l for i, b in enumerate(cpds.best_fits): mfile = os.path.join( outdir, - basename + "__mod{}__.p".format(i), + basename + f"__mod{i}__.p", ) save_model(b, mfile) model_files.append(mfile) @@ -815,7 +821,9 @@ def save_pds(cpds, fname, save_all=False, save_dyn=False, no_auxil=False, save_l def remove_pds(fname): """Remove the pds file and the directory with auxiliary information.""" outdir, _ = splitext_improved(fname) - modelfiles = glob.glob(os.path.join(outdir, fname.replace(HEN_FILE_EXTENSION, "__mod*__.p"))) + modelfiles = glob.glob( + os.path.join(outdir, fname.replace(HEN_FILE_EXTENSION, "__mod*__.p")) + ) for mfile in modelfiles: os.unlink(mfile) if os.path.exists(outdir): @@ -915,8 +923,6 @@ def _save_data_pickle(struct, fname, kind="data"): with open(fname, "wb") as fobj: pickle.dump(struct, fobj) - return - def _load_data_nc(fname): """Load generic data in netcdf format.""" @@ -928,7 +934,7 @@ def _load_data_nc(fname): if k in keys_to_delete: continue - if str(contents[k]) == str("__hen__None__type__"): + if str(contents[k]) == "__hen__None__type__": contents[k] = None if k[-2:] in ["_I", "_L", "_F", "_k"]: @@ -1033,7 +1039,9 @@ def _save_data_nc(struct, fname, kind="data"): # If a (long)double, split it in integer + floating part. # If the number is below zero, also use a logarithm of 10 before # that, so that we don't lose precision - var_I, var_F, var_log10, kind_str = _split_high_precision_number(k, var, probesize) + var_I, var_F, var_log10, kind_str = _split_high_precision_number( + k, var, probesize + ) values.extend([var_I, var_log10, var_F, kind_str]) formats.extend(["i8", "i8", "f8", str]) varnames.extend([k + "_I", k + "_L", k + "_F", k + "_k"]) @@ -1115,7 +1123,7 @@ def save_as_qdp(arrays, errors=None, filename="out.qdp", mode="w"): - an array of len-2 lists for non-symmetric errors (e.g. [[errm1, errp1], [errm2, errp2], [errm3, errp3], ...]) - Other parameters + Other Parameters ---------------- mode : str the file access mode, to be passed to the open() function. Can be 'w' @@ -1156,7 +1164,7 @@ def save_as_qdp(arrays, errors=None, filename="out.qdp", mode="w"): for i in range(length): for idw, d in enumerate(data_to_write): print(d[i], file=outfile, end=" ") - print("", file=outfile) + print(file=outfile) outfile.close() @@ -1185,12 +1193,12 @@ def save_as_ascii(cols, filename="out.txt", colnames=None, append=False): print("#", file=txtfile, end=" ") for i_c, c in enumerate(cols): print(colnames[i_c], file=txtfile, end=" ") - print("", file=txtfile) + print(file=txtfile) for i in range(lcol): for c in cols: print(c[i], file=txtfile, end=" ") - print("", file=txtfile) + print(file=txtfile) txtfile.close() return 0 @@ -1198,8 +1206,8 @@ def save_as_ascii(cols, filename="out.txt", colnames=None, append=False): def print_fits_info(fits_file, hdu=1): """Print general info about an observation.""" from astropy.io import fits as pf - from astropy.units import Unit from astropy.time import Time + from astropy.units import Unit lchdulist = pf.open(fits_file) @@ -1225,7 +1233,7 @@ def print_fits_info(fits_file, hdu=1): print("ObsID: {0}\n".format(info["OBS_ID"])) print("Date: {0} -- {1}\n".format(info["Start"], info["Stop"])) - print("Date (MJD): {0} -- {1}\n".format(start_mjd, stop_mjd)) + print(f"Date (MJD): {start_mjd} -- {stop_mjd}\n") print("Instrument: {0}/{1}\n".format(info["Telescope"], info["Instrument"])) print("Target: {0}\n".format(info["Target"])) print("N. Events: {0}\n".format(info["N. events"])) @@ -1236,8 +1244,6 @@ def print_fits_info(fits_file, hdu=1): def main(args=None): """Main function called by the `HENreadfile` command line script.""" - from astropy.time import Time - import astropy.units as u import argparse description = "Print the content of HENDRICS files" @@ -1255,7 +1261,7 @@ def main(args=None): for fname in args.files: print() print("-" * len(fname)) - print("{0}".format(fname)) + print(f"{fname}") print("-" * len(fname)) if fname.endswith(".fits") or fname.endswith(".evt"): print("This FITS file contains:", end="\n\n") @@ -1312,7 +1318,7 @@ def save_model(model, fname="model.p", constraints=None): fname : str, default 'models.p' The output file name - Other parameters + Other Parameters ---------------- constraints: dict Additional model constraints. Ignored for astropy models. @@ -1324,7 +1330,9 @@ def save_model(model, fname="model.p", constraints=None): nargs = model.__code__.co_argcount nkwargs = len(model.__defaults__) if not nargs - nkwargs == 1: - raise TypeError("Accepted callable models have only one " "non-keyword argument") + raise TypeError( + "Accepted callable models have only one " "non-keyword argument" + ) modeldata["kind"] = "callable" modeldata["constraints"] = constraints else: @@ -1380,7 +1388,9 @@ def load_model(modelstring): nargs = model.__code__.co_argcount nkwargs = len(model.__defaults__) if not nargs - nkwargs == 1: - raise TypeError("Accepted callable models have only one " "non-keyword argument") + raise TypeError( + "Accepted callable models have only one " "non-keyword argument" + ) return model, "callable", constraints @@ -1416,6 +1426,7 @@ def find_file_in_allowed_paths(fname, other_paths=None): def main_filter_events(args=None): import argparse + from .base import _add_default_args, check_negative_numbers_in_args description = "Filter events" diff --git a/hendrics/lcurve.py b/hendrics/lcurve.py index 0beb23f3..9512471e 100644 --- a/hendrics/lcurve.py +++ b/hendrics/lcurve.py @@ -1,25 +1,35 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """Light curve-related functions.""" +import copy import os import warnings -import copy -from astropy import log + import numpy as np -from astropy.logger import AstropyUserWarning +from stingray.gti import contiguous_regions, create_gti_mask, cross_gtis from stingray.lightcurve import Lightcurve from stingray.utils import assign_value_if_none -from stingray.gti import create_gti_mask, cross_gtis, contiguous_regions + +from astropy import log +from astropy.logger import AstropyUserWarning + from .base import ( _look_for_array_in_array, + deorbit_events, hen_root, - mkdir_p, - interpret_bintime, histogram, + interpret_bintime, + mkdir_p, + splitext_improved, +) +from .io import ( + HEN_FILE_EXTENSION, + get_file_type, + high_precision_keyword_read, + load_events, + load_lcurve, + save_lcurve, ) -from .io import load_events, save_lcurve, load_lcurve -from .io import HEN_FILE_EXTENSION, high_precision_keyword_read, get_file_type -from .base import deorbit_events, splitext_improved def join_lightcurve_objs(lclist): @@ -96,6 +106,7 @@ def join_lightcurves(lcfilelist, outfile="out_lc" + HEN_FILE_EXTENSION): List of input file names outfile : Output light curve + See Also -------- scrunch_lightcurves : Create a single light curve from input light @@ -159,7 +170,6 @@ def scrunch_lightcurve_objs(lclist): >>> assert np.all(lcC.counts == [2, 4, 5, 6]) >>> assert np.all(lcC.instr == 'bu1,bu2') """ - instrs = [lc.instr for lc in lclist] gti_lists = [lc.gti for lc in lclist] gti = cross_gtis(gti_lists) @@ -178,7 +188,9 @@ def scrunch_lightcurve_objs(lclist): return lc0 -def scrunch_lightcurves(lcfilelist, outfile="out_scrlc" + HEN_FILE_EXTENSION, save_joint=False): +def scrunch_lightcurves( + lcfilelist, outfile="out_scrlc" + HEN_FILE_EXTENSION, save_joint=False +): """Create a single light curve from input light curves. Light curves are appended when they cover different times, and summed when @@ -222,7 +234,9 @@ def scrunch_lightcurves(lcfilelist, outfile="out_scrlc" + HEN_FILE_EXTENSION, sa return lc0 -def filter_lc_gtis(lc, safe_interval=None, delete=False, min_length=0, return_borders=False): +def filter_lc_gtis( + lc, safe_interval=None, delete=False, min_length=0, return_borders=False +): """Filter a light curve for GTIs. Parameters @@ -374,7 +388,8 @@ def lcurve_from_events( elif e_interval is not None and np.all(np.array(e_interval) > 0): if not hasattr(evdata, "energy") or evdata.energy is None: raise ValueError( - "No energy information is present in the file." + " Did you run HENcalibrate?" + "No energy information is present in the file." + + " Did you run HENcalibrate?" ) es = evdata.energy good = np.logical_and(es > e_interval[0], es <= e_interval[1]) @@ -390,7 +405,9 @@ def lcurve_from_events( ) # Assign default value if None - outfile = assign_value_if_none(outfile, hen_root(f) + tag + deorbit_tag + weight_on_tag + "_lc") + outfile = assign_value_if_none( + outfile, hen_root(f) + tag + deorbit_tag + weight_on_tag + "_lc" + ) # Take out extension from name, if present, then give extension. This # avoids multiple extensions @@ -448,10 +465,12 @@ def lcurve_from_events( lc.instr = instr lc.e_interval = e_interval - lc = filter_lc_gtis(lc, safe_interval=safe_interval, delete=False, min_length=min_length) + lc = filter_lc_gtis( + lc, safe_interval=safe_interval, delete=False, min_length=min_length + ) if len(lc.gti) == 0: - warnings.warn("No GTIs above min_length ({0}s) found.".format(min_length)) + warnings.warn(f"No GTIs above min_length ({min_length}s) found.") return lc.header = None @@ -463,7 +482,7 @@ def lcurve_from_events( outfiles = [] for ib, l0 in enumerate(lcs): - local_tag = tag + "_gti{:03d}".format(ib) + local_tag = tag + f"_gti{ib:03d}" outf = hen_root(outfile) + local_tag + "_lc" + HEN_FILE_EXTENSION if noclobber and os.path.exists(outf): warnings.warn("File exists, and noclobber option used. Skipping") @@ -535,11 +554,12 @@ def lcurve_from_fits( # TODO: # treat consistently TDB, UTC, TAI, etc. This requires some documentation # reading. For now, we assume TDB - from astropy.io import fits as pf - from astropy.time import Time import numpy as np from stingray.gti import create_gti_from_condition + from astropy.io import fits as pf + from astropy.time import Time + outfile = assign_value_if_none(outfile, hen_root(fits_file) + "_lc") outfile = outfile.replace(HEN_FILE_EXTENSION, "") + HEN_FILE_EXTENSION outdir = assign_value_if_none(outdir, os.path.dirname(os.path.abspath(fits_file))) @@ -622,7 +642,8 @@ def lcurve_from_fits( dt *= 86400 except Exception: warnings.warn( - "Assuming that TIMEDEL is the median difference between the" " light curve times", + "Assuming that TIMEDEL is the median difference between the" + " light curve times", AstropyUserWarning, ) dt = np.median(np.diff(time)) @@ -759,7 +780,7 @@ def _baseline_lightcurves(lcurves, outroot, p, lam): if outroot is None: outroot = hen_root(f) + "_lc_baseline" else: - outroot = outroot_save + "_{}".format(i) + outroot = outroot_save + f"_{i}" ftype, lc = get_file_type(f) baseline = lc.baseline(p, lam) lc.base = baseline @@ -771,7 +792,7 @@ def _wrap_lc(args): try: return lcurve_from_events(f, **kwargs) except Exception as e: - warnings.warn("HENlcurve exception: {0}".format(str(e))) + warnings.warn(f"HENlcurve exception: {str(e)}") raise @@ -780,7 +801,7 @@ def _wrap_txt(args): try: return lcurve_from_txt(f, **kwargs) except Exception as e: - warnings.warn("HENlcurve exception: {0}".format(str(e))) + warnings.warn(f"HENlcurve exception: {str(e)}") return [] @@ -789,7 +810,7 @@ def _wrap_fits(args): try: return lcurve_from_fits(f, **kwargs) except Exception as e: - warnings.warn("HENlcurve exception: {0}".format(str(e))) + warnings.warn(f"HENlcurve exception: {str(e)}") return [] @@ -835,7 +856,7 @@ def _execute_lcurve(args): outname, ext = splitext_improved(outfile) for i in range(na): if na > 1: - outname = outfile + "_{0}".format(i) + outname = outfile + f"_{i}" arglist[i][1]["outfile"] = outname # ------------------------------------------------------------------------- @@ -862,6 +883,7 @@ def _execute_lcurve(args): def main(args=None): """Main function called by the `HENlcurve` command line script.""" import argparse + from .base import _add_default_args, check_negative_numbers_in_args description = ( @@ -920,7 +942,9 @@ def main(args=None): default=False, action="store_true", ) - parser.add_argument("-d", "--outdir", type=str, default=None, help="Output directory") + parser.add_argument( + "-d", "--outdir", type=str, default=None, help="Output directory" + ) parser.add_argument( "--noclobber", help="Do not overwrite existing files", @@ -945,7 +969,9 @@ def main(args=None): type=str, help="Use a given attribute of the event list as weights for the light curve", ) - parser = _add_default_args(parser, ["deorbit", "output", "loglevel", "debug", "nproc"]) + parser = _add_default_args( + parser, ["deorbit", "output", "loglevel", "debug", "nproc"] + ) args = check_negative_numbers_in_args(args) args = parser.parse_args(args) diff --git a/hendrics/ml_timing.py b/hendrics/ml_timing.py index 5c27e022..68cf129b 100644 --- a/hendrics/ml_timing.py +++ b/hendrics/ml_timing.py @@ -1,9 +1,11 @@ import copy + import numpy as np -from .base import vectorize, njit, int64, float32, float64 from scipy.interpolate import interp1d from scipy.optimize import minimize +from .base import float32, float64, int64, njit, vectorize + try: from statsmodels.tools.numdiff import approx_hess3 @@ -132,7 +134,7 @@ def normalized_template_func(template, tomax=True, subtract_min=True): template : array-like The input template profile - Other parameters + Other Parameters ---------------- tomax: bool, default True Make the maximum of the profile phase 0 @@ -177,7 +179,7 @@ def normalized_template(template, tomax=False, subtract_min=True): template : array-like The input template profile - Other parameters + Other Parameters ---------------- tomax: bool, default True Make the maximum of the profile phase 0 @@ -192,7 +194,9 @@ def normalized_template(template, tomax=False, subtract_min=True): """ dph = 1 / template.size phase = np.arange(dph / 2, 1, dph) - return normalized_template_func(template, tomax=tomax, subtract_min=subtract_min)(phase) + return normalized_template_func(template, tomax=tomax, subtract_min=subtract_min)( + phase + ) # def estimate_errors(best_fit_templ, ntrial=100, profile_err=None): @@ -282,7 +286,7 @@ def _guess_start_pars(profile, template, fit_base=True, mean_phase=None): dph = 1 / profile.size if mean_phase is None: - mean_phase = ((np.argmax(profile) - np.argmax(template))) * dph + mean_phase = (np.argmax(profile) - np.argmax(template)) * dph if fit_base: amp_tr = (maxp - minp) / (maxt - mint) @@ -325,7 +329,7 @@ def ml_pulsefit( template : array-like The input template - Other parameters + Other Parameters ---------------- profile_err : float, default None The error bars on each bin of the pulse profile. diff --git a/hendrics/modeling.py b/hendrics/modeling.py index 0e1cc991..351c6a1a 100644 --- a/hendrics/modeling.py +++ b/hendrics/modeling.py @@ -1,18 +1,23 @@ -import os import copy +import os import numpy as np -from astropy import log from stingray.modeling import fit_powerspectrum -from .io import load_model, load_pds, save_model, save_pds, HEN_FILE_EXTENSION + +from astropy import log + +from .io import HEN_FILE_EXTENSION, load_model, load_pds, save_model, save_pds def main_model(args=None): """Main function called by the `HENfspec` command line script.""" import argparse + from .base import _add_default_args, check_negative_numbers_in_args - description = "Fit frequency spectra (PDS, CPDS, cospectrum) " "with user-defined models" + description = ( + "Fit frequency spectra (PDS, CPDS, cospectrum) " "with user-defined models" + ) parser = argparse.ArgumentParser(description=description) parser.add_argument("files", help="List of light curve files", nargs="+") diff --git a/hendrics/phaseogram.py b/hendrics/phaseogram.py index b69ded33..f66e54c3 100644 --- a/hendrics/phaseogram.py +++ b/hendrics/phaseogram.py @@ -1,31 +1,27 @@ """Interactive phaseogram.""" -import copy import argparse +import copy import warnings from abc import abstractmethod -from scipy.interpolate import interp1d +import matplotlib.pyplot as plt import numpy as np +from matplotlib.gridspec import GridSpec +from matplotlib.widgets import Button, Slider +from scipy.interpolate import interp1d +from stingray.pulse.search import phaseogram +from stingray.utils import assign_value_if_none + from astropy import log from astropy.logger import AstropyUserWarning from astropy.stats import poisson_conf_interval -from stingray.pulse.search import phaseogram -from stingray.utils import assign_value_if_none -import matplotlib.pyplot as plt -from matplotlib.widgets import Slider, Button -from matplotlib.gridspec import GridSpec -from scipy.ndimage import gaussian_filter1d -from .base import normalize_dyn_profile -from .io import load_events, load_folding -from .fold import filter_energy -from .fold import get_TOAs_from_events -from .fold import create_default_template -from .base import hen_root, deorbit_events, get_model +from .base import deorbit_events, get_model, hen_root, normalize_dyn_profile from .efsearch import h_test -from .ml_timing import normalized_template, ml_pulsefit - +from .fold import create_default_template, filter_energy, get_TOAs_from_events +from .io import load_events, load_folding +from .ml_timing import ml_pulsefit, normalized_template DEFAULT_COLORMAP = "cubehelix" @@ -62,7 +58,7 @@ def normalized_phaseogram(norm, *args, **kwargs): return phas, phases, times, additional_info -class BasePhaseogram(object): +class BasePhaseogram: def __init__( self, ev_times, @@ -94,7 +90,7 @@ def __init__( freq : float Frequency of pulsation - Other parameters + Other Parameters ---------------- nph : int Number of phase bins in the profile @@ -201,8 +197,12 @@ def __init__( self.phases, self.times = phases, times vmin = None - self.pcolor = ax.pcolormesh(phases, times, self.phaseogr.T, cmap=self.colormap, vmin=vmin) - self.colorbar = plt.colorbar(self.pcolor, cax=colorbax, orientation="horizontal") + self.pcolor = ax.pcolormesh( + phases, times, self.phaseogr.T, cmap=self.colormap, vmin=vmin + ) + self.colorbar = plt.colorbar( + self.pcolor, cax=colorbax, orientation="horizontal" + ) ax.set_xlabel("Phase") def s2d(x): @@ -223,7 +223,9 @@ def d2s(x): self.lines = [] self.line_phases = np.arange(-2, 3, 0.5) for ph0 in self.line_phases: - (newline,) = ax.plot(np.zeros_like(times) + ph0, times, zorder=10, lw=2, color="w") + (newline,) = ax.plot( + np.zeros_like(times) + ph0, times, zorder=10, lw=2, color="w" + ) self.lines.append(newline) ax.set_xlim([0, 2]) @@ -242,19 +244,29 @@ def newax_fn(*args, **kwargs): self._construct_widgets(**kwargs) self.closeax = self.fig.add_axes([0.15, 0.020, 0.15, 0.04]) - self.button_close = Button(self.closeax, "Quit", color=axcolor, hovercolor="0.8") + self.button_close = Button( + self.closeax, "Quit", color=axcolor, hovercolor="0.8" + ) self.recalcax = self.fig.add_axes([0.3, 0.020, 0.15, 0.04]) - self.button_recalc = Button(self.recalcax, "Recalculate", color=axcolor, hovercolor="0.975") + self.button_recalc = Button( + self.recalcax, "Recalculate", color=axcolor, hovercolor="0.975" + ) self.resetax = self.fig.add_axes([0.45, 0.020, 0.15, 0.04]) - self.button_reset = Button(self.resetax, "Reset", color=axcolor, hovercolor="0.975") + self.button_reset = Button( + self.resetax, "Reset", color=axcolor, hovercolor="0.975" + ) self.zoominax = self.fig.add_axes([0.6, 0.020, 0.1, 0.04]) - self.button_zoomin = Button(self.zoominax, "+Zoom", color=axcolor, hovercolor="0.975") + self.button_zoomin = Button( + self.zoominax, "+Zoom", color=axcolor, hovercolor="0.975" + ) self.zoomoutax = self.fig.add_axes([0.7, 0.020, 0.1, 0.04]) - self.button_zoomout = Button(self.zoomoutax, "-Zoom", color=axcolor, hovercolor="0.975") + self.button_zoomout = Button( + self.zoomoutax, "-Zoom", color=axcolor, hovercolor="0.975" + ) self.toaax = self.fig.add_axes([0.8, 0.020, 0.1, 0.04]) self.button_toa = Button(self.toaax, "TOA", color=axcolor, hovercolor="0.975") @@ -270,17 +282,25 @@ def newax_fn(*args, **kwargs): prof = np.sum(np.nan_to_num(self.unnorm_phaseogr), axis=1) nbin = len(prof) phas = np.linspace(0, 2, nbin + 1)[:-1] - (self.profile_fixed,) = self.profax.plot(phas, prof, drawstyle="steps-post", color="grey") - (self.profile,) = self.profax.plot(phas, prof, drawstyle="steps-post", color="k") + (self.profile_fixed,) = self.profax.plot( + phas, prof, drawstyle="steps-post", color="grey" + ) + (self.profile,) = self.profax.plot( + phas, prof, drawstyle="steps-post", color="k" + ) mean = np.mean(prof) - low, high = poisson_conf_interval(mean, interval="frequentist-confidence", sigma=2) + low, high = poisson_conf_interval( + mean, interval="frequentist-confidence", sigma=2 + ) self.profax.fill_between(phas, low, high, alpha=0.5) z2_label = get_H_label(phas, prof) - self.proftext = self.profax.text(0.1, 0.8, z2_label, transform=self.profax.transAxes) + self.proftext = self.profax.text( + 0.1, 0.8, z2_label, transform=self.profax.transAxes + ) if not test and not plot_only: plt.show() if plot_only: - plt.savefig(self.label + "_{:.10f}Hz.png".format(self.freq)) + plt.savefig(self.label + f"_{self.freq:.10f}Hz.png") @abstractmethod def _construct_widgets(self, **kwargs): # pragma: no cover @@ -296,7 +316,8 @@ def recalculate(self, event): # pragma: no cover def toa(self, event): # pragma: no cover warnings.warn( - "This function was not implemented for this Phaseogram. " "Try the basic one.", + "This function was not implemented for this Phaseogram. " + "Try the basic one.", AstropyUserWarning, ) @@ -407,7 +428,6 @@ def _line_delay_fun(self, times): # pragma: no cover @abstractmethod def _delay_fun(self, times): # pragma: no cover """This is the delay function _without_ frequency derivatives.""" - pass @abstractmethod def _read_sliders(self): # pragma: no cover @@ -456,29 +476,33 @@ def get_timing_model_string(self): tm_string = "" if self.mjdref is not None: - tm_string += "PEPOCH {}\n".format(self.pepoch / 86400 + self.mjdref) - tm_string += "PSRJ {}\n".format(self.object) + tm_string += f"PEPOCH {self.pepoch / 86400 + self.mjdref}\n" + tm_string += f"PSRJ {self.object}\n" if self.position is not None: - tm_string += "RAJ {}\n".format(self.position.ra.to_string("hour", sep=":")) - tm_string += "DECJ {}\n".format(self.position.dec.to_string(sep=":")) + tm_string += "RAJ {}\n".format( + self.position.ra.to_string("hour", sep=":") + ) + tm_string += "DECJ {}\n".format( + self.position.dec.to_string(sep=":") + ) - tm_string += "F0 {}\n".format(self.freq) - tm_string += "F1 {}\n".format(self.fdot) - tm_string += "F2 {}\n".format(self.fddot) + tm_string += f"F0 {self.freq}\n" + tm_string += f"F1 {self.fdot}\n" + tm_string += f"F2 {self.fddot}\n" if hasattr(self, "orbital_period") and self.orbital_period is not None: tm_string += "BINARY BT\n" - tm_string += "PB {}\n".format(self.orbital_period / 86400) - tm_string += "A1 {}\n".format(self.asini) + tm_string += f"PB {self.orbital_period / 86400}\n" + tm_string += f"A1 {self.asini}\n" if self.mjdref is not None: - tm_string += "T0 {}\n".format(self.t0 / 86400 + self.mjdref) - tm_string += "T0(MET) {}\n".format(self.t0) - tm_string += "PB(s) {}\n".format(self.orbital_period) + tm_string += f"T0 {self.t0 / 86400 + self.mjdref}\n" + tm_string += f"T0(MET) {self.t0}\n" + tm_string += f"PB(s) {self.orbital_period}\n" - tm_string += "# PEPOCH(MET) {}\n".format(self.pepoch) + tm_string += f"# PEPOCH(MET) {self.pepoch}\n" start, stop = self.gti.min(), self.gti.max() - tm_string += "START {}\n".format(start / 86400 + self.mjdref) - tm_string += "FINISH {}\n".format(stop / 86400 + self.mjdref) + tm_string += f"START {start / 86400 + self.mjdref}\n" + tm_string += f"FINISH {stop / 86400 + self.mjdref}\n" return tm_string @@ -692,7 +716,7 @@ def __init__(self, *args, **kwargs): freq : float Frequency of pulsation - Other parameters + Other Parameters ---------------- orbital_period : float orbital period in seconds @@ -771,7 +795,9 @@ def _line_delay_fun(self, times): orbital_period, asini, t0 = self._read_sliders() new_values = asini * np.sin(2 * np.pi * (times - t0) / orbital_period) - old_values = self.asini * np.sin(2 * np.pi * (times - self.t0) / (self.orbital_period)) + old_values = self.asini * np.sin( + 2 * np.pi * (times - self.t0) / (self.orbital_period) + ) return (new_values - old_values) * self.freq def _delay_fun(self, times): @@ -851,8 +877,8 @@ def run_interactive_phaseogram( emax=None, colormap=DEFAULT_COLORMAP, ): - from astropy.io.fits import Header from astropy.coordinates import SkyCoord + from astropy.io.fits import Header events = load_events(event_file) if emin is not None or emax is not None: @@ -964,8 +990,12 @@ def main_phaseogram(args=None): help="Initial frequency to fold", default=None, ) - parser.add_argument("--fdot", type=float, required=False, help="Initial fdot", default=0) - parser.add_argument("--fddot", type=float, required=False, help="Initial fddot", default=0) + parser.add_argument( + "--fdot", type=float, required=False, help="Initial fdot", default=0 + ) + parser.add_argument( + "--fddot", type=float, required=False, help="Initial fddot", default=0 + ) parser.add_argument( "--periodogram", type=str, @@ -1046,7 +1076,9 @@ def main_phaseogram(args=None): with log.log_to_file("HENphaseogram.log"): if args.periodogram is None and args.freq is None: - raise ValueError("One of -f or --periodogram arguments MUST be " "specified") + raise ValueError( + "One of -f or --periodogram arguments MUST be " "specified" + ) elif args.periodogram is not None: periodogram = load_folding(args.periodogram) frequency = float(periodogram.peaks[0]) diff --git a/hendrics/phasetag.py b/hendrics/phasetag.py index d94bffdd..abd2c083 100644 --- a/hendrics/phasetag.py +++ b/hendrics/phasetag.py @@ -1,19 +1,20 @@ #!/usr/bin/env python -import os import argparse import warnings -import numpy as np + import matplotlib.pyplot as plt +import numpy as np +from stingray.io import load_events_and_gtis, ref_mjd +from stingray.pulse.pulsar import phase_exposure, pulse_phase + import astropy.io.fits as pf from astropy import log from astropy.logger import AstropyUserWarning -from stingray.io import load_events_and_gtis, ref_mjd -from stingray.pulse.pulsar import pulse_phase, phase_exposure -from .io import is_string, save_as_qdp from .base import _assign_value_if_none, hen_root, splitext_improved from .fold import fit_profile, std_fold_fit_func +from .io import is_string, save_as_qdp def outfile_name(file): @@ -28,7 +29,6 @@ def outfile_name(file): >>> outfile_name('file.s.a.evct') 'file.s.a_phasetag.evct' """ - root, ext = splitext_improved(file) return root + "_phasetag" + ext @@ -58,7 +58,7 @@ def phase_tag( understand. Otherwise, this is a list of frequency derivatives [F0, F1, F2, ...] - Other parameters + Other Parameters ---------------- gti : [[g0_0, g0_1], [g1_0, g1_1], ...] Good time intervals @@ -101,7 +101,9 @@ def phase_tag( f = frequency_derivatives[0] phase = pulse_phase(times, *frequency_derivatives, to_1=False) - gti_phases = pulse_phase((gti_mjd - pepoch) * 86400, *frequency_derivatives, to_1=False) + gti_phases = pulse_phase( + (gti_mjd - pepoch) * 86400, *frequency_derivatives, to_1=False + ) # ------- now apply period derivatives ------ @@ -116,11 +118,15 @@ def phase_tag( phase_to1 = phase - np.floor(phase) raw_profile, bins = np.histogram(phase_to1, bins=np.linspace(0, 1, nbin + 1)) - exposure = phase_exposure(gti_phases[0, 0], gti_phases[-1, 1], 1, nbin=nbin, gti=gti_phases) + exposure = phase_exposure( + gti_phases[0, 0], gti_phases[-1, 1], 1, nbin=nbin, gti=gti_phases + ) profile = raw_profile / exposure profile_err = np.sqrt(raw_profile) / exposure - sinpars, bu, bu = fit_profile(profile, profile_err, nperiods=2, baseline=True, debug=test) + sinpars, bu, bu = fit_profile( + profile, profile_err, nperiods=2, baseline=True, debug=test + ) fine_phases = np.linspace(0, 2, 1000 * 2) fitted_profile = std_fold_fit_func(sinpars, fine_phases) maxp = np.argmax(fitted_profile) @@ -137,7 +143,9 @@ def phase_tag( raw_profile, bins = np.histogram(phase_to1, bins=np.linspace(0, 1, nbin + 1)) - exposure = phase_exposure(gti_phases[0, 0], gti_phases[-1, 1], 1, nbin=nbin, gti=gti_phases) + exposure = phase_exposure( + gti_phases[0, 0], gti_phases[-1, 1], 1, nbin=nbin, gti=gti_phases + ) if np.any(np.logical_or(exposure != exposure, exposure == 0)): warnings.warn( "Exposure has NaNs or zeros. Profile is not normalized", @@ -202,7 +210,7 @@ def phase_tag_fits( understand. Otherwise, this is a list of frequency derivatives [F0, F1, F2, ...] - Other parameters + Other Parameters ---------------- nbin : int Number of nbin in the pulsed profile @@ -225,7 +233,6 @@ def phase_tag_fits( hduname : str, default 'EVENTS' Name of the HDU containing the event list """ - outfile = outfile_name(filename) evreturns = load_events_and_gtis( filename, @@ -237,7 +244,11 @@ def phase_tag_fits( mjdref = ref_mjd(filename) results = phase_tag( - evreturns.ev_list, parameter_info, gti=evreturns.gti_list, mjdref=mjdref, **kwargs + evreturns.ev_list, + parameter_info, + gti=evreturns.gti_list, + mjdref=mjdref, + **kwargs, ) if results.figure is not None: results.figure.savefig(hen_root(filename) + ".pdf") @@ -277,7 +288,9 @@ def phase_tag_fits( if create: # then, create new column with orbital demodulation - newcol = pf.Column(name="Orbit_bary", format="1D", unit="s", array=results.ev_list) + newcol = pf.Column( + name="Orbit_bary", format="1D", unit="s", array=results.ev_list + ) # append it to new table newlist.append(newcol) @@ -304,7 +317,9 @@ def phase_tag_fits( newrec = pf.FITS_rec.from_columns(coldefs) # and new hdu - newtbhdu = pf.BinTableHDU(data=newrec, header=tbhdu.header.copy(), name=hduname, uint=False) + newtbhdu = pf.BinTableHDU( + data=newrec, header=tbhdu.header.copy(), name=hduname, uint=False + ) # Copy primary HDU from old file prihdu = hdulist[0].copy() diff --git a/hendrics/plot.py b/hendrics/plot.py index 5ec51117..847a7cfd 100644 --- a/hendrics/plot.py +++ b/hendrics/plot.py @@ -1,30 +1,37 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """Quicklook plots.""" -import warnings -import os import copy +import os +import warnings from collections.abc import Iterable -import numpy as np + import matplotlib.colors as colors +import numpy as np from stingray.gti import create_gti_mask -from astropy.modeling.models import Const1D +from stingray.power_colors import plot_hues, plot_power_colors + +from astropy import log from astropy.modeling import Model +from astropy.modeling.models import Const1D from astropy.stats import poisson_conf_interval -from astropy import log from astropy.table import Table -from .efsearch import analyze_qffa_results -from .fold import fold_events, filter_energy -from .io import load_events, load_lcurve, load_pds -from .io import load_data, get_file_type -from .io import is_string, save_as_qdp -from .io import HEN_FILE_EXTENSION -from .io import find_file_in_allowed_paths -from .base import _assign_value_if_none +from .base import _assign_value_if_none, deorbit_events from .base import pds_detection_level as detection_level -from .base import deorbit_events -from stingray.power_colors import plot_hues, plot_power_colors +from .efsearch import analyze_qffa_results +from .fold import filter_energy, fold_events +from .io import ( + HEN_FILE_EXTENSION, + find_file_in_allowed_paths, + get_file_type, + is_string, + load_data, + load_events, + load_lcurve, + load_pds, + save_as_qdp, +) def _next_color(ax): @@ -87,7 +94,7 @@ def rescale_plot_units(values): """ span = values.max() - values.min() - oom = int(np.log10((span))) - 1 + oom = int(np.log10(span)) - 1 if abs(oom) <= 2: return 0.0, 0, values @@ -109,7 +116,7 @@ def plot_generic( if is_string(fnames): fnames = [fnames] - figname = _assign_value_if_none(figname, "{0} vs {1}".format(vars[1], vars[0])) + figname = _assign_value_if_none(figname, f"{vars[1]} vs {vars[0]}") plt.figure(figname) ax = plt.gca() if xlog: @@ -176,7 +183,6 @@ def _get_const(models): >>> _get_const('avdsfa') """ - if isinstance(models, Const1D): return models.amplitude.value @@ -204,9 +210,15 @@ def plot_powercolors(fnames): ts = load_data(fnames) - plot_power_colors(ts["pc1"], ts["pc1_err"], ts["pc2"], ts["pc2_err"], plot_spans=True) - plot_hues(ts["rms"], ts["rms_err"], ts["pc1"], ts["pc2"], polar=True, plot_spans=True) - plot_hues(ts["rms"], ts["rms_err"], ts["pc1"], ts["pc2"], polar=False, plot_spans=True) + plot_power_colors( + ts["pc1"], ts["pc1_err"], ts["pc2"], ts["pc2_err"], plot_spans=True + ) + plot_hues( + ts["rms"], ts["rms_err"], ts["pc1"], ts["pc2"], polar=True, plot_spans=True + ) + plot_hues( + ts["rms"], ts["rms_err"], ts["pc1"], ts["pc2"], polar=False, plot_spans=True + ) return ts @@ -219,9 +231,8 @@ def plot_pds( white_sub=False, ): """Plot a list of PDSs, or a single one.""" - - from scipy.optimize import curve_fit import matplotlib.pyplot as plt + from scipy.optimize import curve_fit if is_string(fnames): fnames = [fnames] @@ -286,7 +297,7 @@ def plot_pds( plt.plot( freq, func(freq), - label="Model {}".format(i + 1), + label=f"Model {i + 1}", zorder=20, color="k", ) @@ -295,7 +306,7 @@ def plot_pds( const = _get_const(models) if const is None: p, pcov = curve_fit(_baseline_fun, freq, pds, p0=[2], sigma=epds) - log.info("White noise level is {0}".format(p[0])) + log.info(f"White noise level is {p[0]}") const = p[0] pds -= const @@ -310,7 +321,7 @@ def plot_pds( plt.plot( freq, freq * (func(freq) - const), - label="Model {}".format(i + 1), + label=f"Model {i + 1}", zorder=20, color="k", ) @@ -385,7 +396,7 @@ def plot_cospectrum(fnames, figname=None, xlog=None, ylog=None, output_data_file y = freq[1:] * cospectrum[1:] plt.plot(freq[1:], y, drawstyle="steps-mid", label=fname) for i, func in enumerate(models): - plt.plot(freq, freq * func(freq), label="Model {}".format(i + 1)) + plt.plot(freq, freq * func(freq), label=f"Model {i + 1}") plt.ylabel("Cospectrum * Frequency") else: @@ -394,7 +405,7 @@ def plot_cospectrum(fnames, figname=None, xlog=None, ylog=None, output_data_file plt.ylabel("Cospectrum") for i, func in enumerate(models): - plt.plot(freq, func(freq), label="Model {}".format(i + 1)) + plt.plot(freq, func(freq), label=f"Model {i + 1}") if output_data_file is not None: save_as_qdp([freq[1:], y], filename=output_data_file, mode="a") @@ -405,8 +416,8 @@ def plot_cospectrum(fnames, figname=None, xlog=None, ylog=None, output_data_file def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=None): - from matplotlib import gridspec import matplotlib.pyplot as plt + from matplotlib import gridspec if is_string(fnames): fnames = [fnames] @@ -442,7 +453,7 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No root = os.path.split(fname)[0] parfile = find_file_in_allowed_paths(ef.parfile, [".", root]) if not parfile: - warnings.warn("{} does not exist".format(ef.parfile)) + warnings.warn(f"{ef.parfile} does not exist") else: ef.parfile = parfile @@ -488,7 +499,9 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No mean = np.mean(profile) - low, high = poisson_conf_interval(mean, interval="frequentist-confidence", sigma=1) + low, high = poisson_conf_interval( + mean, interval="frequentist-confidence", sigma=1 + ) ax.axhline(mean) ax.fill_between( @@ -498,7 +511,9 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No label=r"1-$\sigma c.l.$", alpha=0.5, ) - low, high = poisson_conf_interval(mean, interval="frequentist-confidence", sigma=3) + low, high = poisson_conf_interval( + mean, interval="frequentist-confidence", sigma=3 + ) ax.fill_between( [0, 2], [low, low], @@ -516,16 +531,16 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No f"--fdot {fdot} {ef.filename} -n {nbin} --ntimes {ntimes} --norm meansub" ) if ef.parfile and os.path.exists(ef.parfile): - phascommand += " --deorbit-par {}".format(parfile) + phascommand += f" --deorbit-par {parfile}" if hasattr(ef, "emin") and ef.emin is not None: - phascommand += " --emin {}".format(ef.emin) + phascommand += f" --emin {ef.emin}" if hasattr(ef, "emin") and ef.emin is not None: - phascommand += " --emax {}".format(ef.emax) + phascommand += f" --emax {ef.emax}" if hasattr(events, "mjdref") and events.mjdref is not None: - phascommand += " --pepoch {}".format(pepoch) + phascommand += f" --pepoch {pepoch}" - log.info("To see the detailed phaseogram, " "run {}".format(phascommand)) + log.info("To see the detailed phaseogram, " f"run {phascommand}") elif not os.path.exists(ef.filename): warnings.warn(ef.filename + " does not exist") @@ -538,22 +553,22 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No f_mean, f_oom, f_rescale = rescale_plot_units(ef.freq) if f_oom != 0: - flabel = f"Frequency" + flabel = "Frequency" if f_mean != 0.0: flabel = "(" + flabel + f"- {f_mean})" flabel += rf" ($10^{{{f_oom}}}$ Hz)" else: - flabel = f"Frequency (Hz)" + flabel = "Frequency (Hz)" if len(ef.stat.shape) > 1 and ef.stat.shape[0] > 1: fd_mean, fd_oom, fd_rescale = rescale_plot_units(ef.fdots) if fd_oom != 0: - fdlabel = f"Fdot" + fdlabel = "Fdot" if fd_mean != 0.0: fdlabel = "(" + flabel + f" - {fd_mean:g})" fdlabel += rf" ($10^{{{fd_oom}}}$ Hz/s)" else: - fdlabel = f"Fdot (Hz/s)" + fdlabel = "Fdot (Hz/s)" gs = gridspec.GridSpecFromSubplotSpec( 2, @@ -614,10 +629,12 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No cbar = plt.colorbar(pcol, cax=axcolor, ticks=colorticks) if len(cs.allsegs[0]) > 1: - warnings.warn("More than one contour found. " "Frequency estimates might be wrong") + warnings.warn( + "More than one contour found. " "Frequency estimates might be wrong" + ) else: for ax in (axffdot, axf): - ax.axvline(cs.allsegs[0][0][:, 0].min(), label=f"90% conf. lim.") + ax.axvline(cs.allsegs[0][0][:, 0].min(), label="90% conf. lim.") ax.axvline(cs.allsegs[0][0][:, 0].max()) for ax in (axffdot, axfdot): @@ -672,7 +689,11 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No axf.set_ylabel(ef.kind + " stat") axf.legend(loc=4) - if hasattr(ef, "best_fits") and ef.best_fits is not None and not len(ef.stat.shape) > 1: + if ( + hasattr(ef, "best_fits") + and ef.best_fits is not None + and not len(ef.stat.shape) > 1 + ): for f in ef.best_fits: xs = np.linspace(np.min(ef.freq), np.max(ef.freq), len(ef.freq) * 2) plt.plot(xs, f(xs)) @@ -685,7 +706,11 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No out = [ef.freq.flatten(), fdots.flatten(), ef.stat.flatten()] out_err = [None, None, None] - if hasattr(ef, "best_fits") and ef.best_fits is not None and not len(ef.stat.shape) > 1: + if ( + hasattr(ef, "best_fits") + and ef.best_fits is not None + and not len(ef.stat.shape) > 1 + ): for f in ef.best_fits: out.append(f(ef.freq.flatten())) out_err.append(None) @@ -824,6 +849,7 @@ def plot_lc( def main(args=None): """Main function called by the `HENplot` command line script.""" import argparse + from .base import check_negative_numbers_in_args description = "Plot the content of HENDRICS light curves and frequency spectra" @@ -872,8 +898,12 @@ def main(args=None): default=None, action="store_true", ) - parser.add_argument("--xlin", help="Use linear X axis", default=False, action="store_true") - parser.add_argument("--ylin", help="Use linear Y axis", default=False, action="store_true") + parser.add_argument( + "--xlin", help="Use linear X axis", default=False, action="store_true" + ) + parser.add_argument( + "--ylin", help="Use linear Y axis", default=False, action="store_true" + ) parser.add_argument( "--white-sub", help="Subtract Poisson noise (only applies to PDS)", diff --git a/hendrics/power_colors.py b/hendrics/power_colors.py index 3be9880d..20138cea 100644 --- a/hendrics/power_colors.py +++ b/hendrics/power_colors.py @@ -1,20 +1,18 @@ """Functions to calculate power colors.""" # Licensed under a 3-clause BSD style license - see LICENSE.rst -import os import warnings from collections.abc import Iterable + import numpy as np -import matplotlib.pyplot as plt -from scipy.interpolate import interp1d +from stingray import DynamicalCrossspectrum, DynamicalPowerspectrum, StingrayTimeseries +from stingray.gti import cross_two_gtis +from stingray.power_colors import hue_from_power_color from astropy import log -from stingray import StingrayTimeseries, DynamicalPowerspectrum, DynamicalCrossspectrum -from stingray.power_colors import hue_from_power_color -from stingray.gti import cross_two_gtis +from .base import common_name, hen_root, interpret_bintime from .io import HEN_FILE_EXTENSION, load_events, save_timeseries -from .base import hen_root, interpret_bintime, common_name def treat_power_colors( @@ -92,7 +90,9 @@ def treat_power_colors( ) good = (scolor.pc1 > 0) & (scolor.pc2 > 0) if np.any(~good): - warnings.warn("Some (non-log) power colors are negative. Neglecting them", UserWarning) + warnings.warn( + "Some (non-log) power colors are negative. Neglecting them", UserWarning + ) scolor = scolor.apply_mask(good) if outfile is None: @@ -108,6 +108,7 @@ def treat_power_colors( def main(args=None): """Main function called by the `HENcolors` command line script.""" import argparse + from .base import _add_default_args, check_negative_numbers_in_args description = "Calculate color light curves" diff --git a/hendrics/read_events.py b/hendrics/read_events.py index e877001d..0cc09404 100644 --- a/hendrics/read_events.py +++ b/hendrics/read_events.py @@ -1,20 +1,23 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """Read and save event lists from FITS files.""" -import warnings -import copy import os +import warnings + import numpy as np -from astropy import log -from stingray.io import load_events_and_gtis from stingray.events import EventList -from stingray.gti import cross_two_gtis, cross_gtis, check_separate -from stingray.gti import create_gti_from_condition, create_gti_mask -from .io import load_events -from .base import common_name -from .base import hen_root -from .io import save_events -from .io import HEN_FILE_EXTENSION +from stingray.gti import ( + check_separate, + create_gti_from_condition, + create_gti_mask, + cross_gtis, + cross_two_gtis, +) + +from astropy import log + +from .base import common_name, hen_root +from .io import HEN_FILE_EXTENSION, load_events, save_events def treat_event_file( @@ -88,7 +91,9 @@ def treat_event_file( good = lc.counts > 0 new_bad = (~good) & good_gti if np.any(new_bad): - warnings.warn(f"Found zero counts in the light curve at times{lc.time[new_bad]}") + warnings.warn( + f"Found zero counts in the light curve at times{lc.time[new_bad]}" + ) gti = create_gti_from_condition( lc.time, (good_gti & good), safe_interval=bin_time_for_occultations ) @@ -100,7 +105,9 @@ def treat_event_file( detector_id = events.detector_id if randomize_by is not None: - events.time += np.random.uniform(-randomize_by / 2, randomize_by / 2, events.time.size) + events.time += np.random.uniform( + -randomize_by / 2, randomize_by / 2, events.time.size + ) if fill_small_gaps is not None: events = events.fill_bad_time_intervals(fill_small_gaps) @@ -121,7 +128,7 @@ def treat_event_file( for d in detectors: if d is not None: good_det = d == detector_id - outroot_local = "{0}_det{1:02d}".format(outfile_root, d) + outroot_local = f"{outfile_root}_det{d:02d}" else: good_det = np.ones_like(events.time, dtype=bool) @@ -129,7 +136,7 @@ def treat_event_file( outfile = outroot_local + "_ev" + HEN_FILE_EXTENSION if noclobber and os.path.exists(outfile) and (not (gti_split or length_split)): - warnings.warn("{0} exists and using noclobber. Skipping".format(outfile)) + warnings.warn(f"{outfile} exists and using noclobber. Skipping") return if gti_split or (length_split is not None): @@ -144,13 +151,14 @@ def treat_event_file( for ig, g in enumerate(gti_chunks): outfile_local = ( - "{0}_{1}{2:03d}_ev".format(outroot_local, label, ig) + HEN_FILE_EXTENSION + f"{outroot_local}_{label}{ig:03d}_ev" + HEN_FILE_EXTENSION ) good_gti = cross_two_gtis([g], gti) if noclobber and os.path.exists(outfile_local): warnings.warn( - "{0} exists, ".format(outfile_local) + "and noclobber option used. Skipping" + f"{outfile_local} exists, " + + "and noclobber option used. Skipping" ) return good = np.logical_and(events.time >= g[0], events.time < g[1]) @@ -215,7 +223,6 @@ def multiple_event_concatenate(event_lists): >>> assert np.allclose(ev_new.energy, [3, 4, 3, 4, 3, 4]) >>> assert ev_new.pi is None """ - ev_new = EventList() if check_separate(event_lists[0].gti, event_lists[1].gti): @@ -258,7 +265,7 @@ def join_eventlists(event_file1, event_file2, new_event_file=None, ignore_instr= event_file2 : str Second event file - Other parameters + Other Parameters ---------------- new_event_file : str, default None Output event file. If not specified uses `hendrics.utils.common_name` @@ -272,7 +279,9 @@ def join_eventlists(event_file1, event_file2, new_event_file=None, ignore_instr= Output event file """ if new_event_file is None: - new_event_file = common_name(event_file1, event_file2) + "_ev" + HEN_FILE_EXTENSION + new_event_file = ( + common_name(event_file1, event_file2) + "_ev" + HEN_FILE_EXTENSION + ) events1 = load_events(event_file1) events2 = load_events(event_file2) @@ -319,7 +328,7 @@ def join_many_eventlists(eventfiles, new_event_file=None, ignore_instr=False): event_files : list of str List of event files - Other parameters + Other Parameters ---------------- new_event_file : str, default None Output event file. If not specified ``joint_ev`` + HEN_FILE_EXTENSION @@ -345,7 +354,11 @@ def join_many_eventlists(eventfiles, new_event_file=None, ignore_instr=False): if not np.isclose(events.mjdref, first_events.mjdref): warnings.warn(f"{event_file} has a different MJDREF") continue - if hasattr(events, "instr") and not events.instr == first_events.instr and not ignore_instr: + if ( + hasattr(events, "instr") + and not events.instr == first_events.instr + and not ignore_instr + ): warnings.warn(f"{event_file} is from a different instrument") continue elif ignore_instr: @@ -454,11 +467,14 @@ def main_join(args=None): import argparse description = ( - "Read a cleaned event files and saves the relevant " "information in a standard format" + "Read a cleaned event files and saves the relevant " + "information in a standard format" ) parser = argparse.ArgumentParser(description=description) parser.add_argument("files", help="Files to join", type=str, nargs="+") - parser.add_argument("-o", "--output", type=str, help="Name of output file", default=None) + parser.add_argument( + "-o", "--output", type=str, help="Name of output file", default=None + ) parser.add_argument( "--ignore-instr", help="Ignore instrument names in channels", @@ -502,7 +518,8 @@ def main_splitevents(args=None): parser.add_argument( "--overlap", type=float, - help="Overlap factor. 0 for no overlap, 0.5 for " "half-interval overlap, and so on.", + help="Overlap factor. 0 for no overlap, 0.5 for " + "half-interval overlap, and so on.", default=None, ) parser.add_argument( @@ -516,17 +533,21 @@ def main_splitevents(args=None): if args.split_at_mjd is not None: return split_eventlist_at_mjd(args.fname, mjd=args.split_at_mjd) - return split_eventlist(args.fname, max_length=args.length_split, overlap=args.overlap) + return split_eventlist( + args.fname, max_length=args.length_split, overlap=args.overlap + ) def main(args=None): """Main function called by the `HENreadevents` command line script.""" import argparse from multiprocessing import Pool + from .base import _add_default_args, check_negative_numbers_in_args description = ( - "Read a cleaned event files and saves the relevant " "information in a standard format" + "Read a cleaned event files and saves the relevant " + "information in a standard format" ) parser = argparse.ArgumentParser(description=description) parser.add_argument("files", help="List of files", nargs="+") diff --git a/hendrics/rebin.py b/hendrics/rebin.py index 77f6de5a..441ed8bb 100644 --- a/hendrics/rebin.py +++ b/hendrics/rebin.py @@ -1,13 +1,10 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """Functions to rebin light curves and frequency spectra.""" -import numpy as np from astropy import log from .base import get_file_extension -from .io import get_file_type -from .io import save_lcurve, save_pds -from .io import HEN_FILE_EXTENSION +from .io import HEN_FILE_EXTENSION, get_file_type, save_lcurve, save_pds def rebin_file(filename, rebin): @@ -39,6 +36,7 @@ def rebin_file(filename, rebin): def main(args=None): """Main function called by the `HENrebin` command line script.""" import argparse + from .base import _add_default_args, check_negative_numbers_in_args description = "Rebin light curves and frequency spectra. " diff --git a/hendrics/save_as_xspec.py b/hendrics/save_as_xspec.py index eef9cd72..3af93d45 100644 --- a/hendrics/save_as_xspec.py +++ b/hendrics/save_as_xspec.py @@ -2,10 +2,13 @@ """Functions to save data in a Xspec-readable format.""" import subprocess as sp + import numpy as np + from astropy import log -from .io import get_file_type + from .base import get_file_extension +from .io import get_file_type def save_as_xspec(fname, direct_save=False, save_lags=True): @@ -41,7 +44,7 @@ def save_as_xspec(fname, direct_save=False, save_lags=True): np.savetxt(outname, np.transpose([flo, fhi, power, power_err])) if direct_save: - sp.check_call("flx2xsp {0} {1}.pha {1}.rsp".format(outname, outroot).split()) + sp.check_call(f"flx2xsp {outname} {outroot}.pha {outroot}.rsp".split()) if save_lags and ftype == "cpds": lags, lags_err = contents.time_lag() @@ -50,12 +53,15 @@ def save_as_xspec(fname, direct_save=False, save_lags=True): np.transpose([flo, fhi, lags * contents.df, lags_err * contents.df]), ) if direct_save: - sp.check_call("flx2xsp {0} {1}.pha {1}.rsp".format(outname_lags, outroot_lags).split()) + sp.check_call( + f"flx2xsp {outname_lags} {outroot_lags}.pha {outroot_lags}.rsp".split() + ) def main(args=None): """Main function called by the `HEN2xspec` command line script.""" import argparse + from .base import _add_default_args, check_negative_numbers_in_args description = ( diff --git a/hendrics/setup_package.py b/hendrics/setup_package.py index 57e14dc9..a220c977 100644 --- a/hendrics/setup_package.py +++ b/hendrics/setup_package.py @@ -1,7 +1,7 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst -import os import glob +import os ROOT = os.path.dirname(__file__) diff --git a/hendrics/sum_fspec.py b/hendrics/sum_fspec.py index d4325236..3f3c0acc 100644 --- a/hendrics/sum_fspec.py +++ b/hendrics/sum_fspec.py @@ -2,10 +2,10 @@ """Function to sum frequency spectra.""" from astropy import log -from .io import save_pds, get_file_type -from .io import HEN_FILE_EXTENSION + from .base import _assign_value_if_none from .fspec import average_periodograms +from .io import HEN_FILE_EXTENSION, get_file_type, save_pds def sum_fspec(files, outname=None): @@ -46,7 +46,9 @@ def main(args=None): "--outname", type=str, default=None, - help="Output file name for summed (C)PDS. Default:" + " tot_(c)pds" + HEN_FILE_EXTENSION, + help="Output file name for summed (C)PDS. Default:" + + " tot_(c)pds" + + HEN_FILE_EXTENSION, ) args = parser.parse_args(args) diff --git a/hendrics/tests/__init__.py b/hendrics/tests/__init__.py index a01d86e6..90e741cb 100644 --- a/hendrics/tests/__init__.py +++ b/hendrics/tests/__init__.py @@ -14,7 +14,7 @@ def _dummy_par(par, pb=1e20, a1=0.0, f0=1.0): print("DM 0", file=fobj) print(f"PB {pb}", file=fobj) print(f"A1 {a1}", file=fobj) - print(f"OM 0.0", file=fobj) + print("OM 0.0", file=fobj) print("ECC 0.0", file=fobj) print("T0 56000", file=fobj) print("EPHEM DE421", file=fobj) diff --git a/hendrics/tests/test_a_complete_run.py b/hendrics/tests/test_a_complete_run.py index 1535faae..b1fe2c00 100644 --- a/hendrics/tests/test_a_complete_run.py +++ b/hendrics/tests/test_a_complete_run.py @@ -1,43 +1,21 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """Test a full run of the codes from the command line.""" -import shutil import os -import glob import subprocess as sp import numpy as np -from astropy.io.registry import IORegistryError -from astropy import log -from astropy.logger import AstropyUserWarning import pytest -from stingray.lightcurve import Lightcurve + import hendrics as hen -from hendrics.tests import _dummy_par -from hendrics.fold import HAS_PINT +from astropy import log +from astropy.io.registry import IORegistryError from hendrics import ( - fake, - fspec, - base, - binary, - calibrate, - colors, - create_gti, - exposure, - exvar, io, - lcurve, - modeling, - plot, - power_colors, - read_events, - rebin, - save_as_xspec, - timelags, - varenergy, - sum_fspec, ) from hendrics.io import HAS_H5PY +from hendrics.tests import _dummy_par + from . import cleanup_test_dir, find_file_pattern_in_dir try: @@ -51,7 +29,7 @@ # log.basicConfig(filename='HEN.log', level=log.DEBUG, filemode='w') -class TestFullRun(object): +class TestFullRun: """Test how command lines work. Usually considered bad practice, but in this @@ -60,17 +38,23 @@ class TestFullRun(object): Inspired by https://stackoverflow.com/questions/5387299/python-unittest-testcase-execution-order When command line is missing, uses some function calls - """ # NOQA + """ @classmethod def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileA = os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ) cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) - cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) + cls.ev_fileA = os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ) + cls.ev_fileB = os.path.join( + cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION + ) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, @@ -86,8 +70,12 @@ def setup_class(cls): ) hen.read_events.main(command.split()) command = "{} {} -r {}".format( - os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), - os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION), + os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ), + os.path.join( + cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION + ), os.path.join(cls.datadir, "test.rmf"), ) hen.calibrate.main(command.split()) @@ -97,23 +85,31 @@ def setup_class(cls): cls.lcB = os.path.join( os.path.join(cls.datadir, "monol_testB_E3-50_lc" + HEN_FILE_EXTENSION) ) - command = ("{} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " "-o {}").format( - cls.ev_fileAcal, cls.lcA + command = ( + f"{cls.ev_fileAcal} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " + f"-o {cls.lcA}" ) hen.lcurve.main(command.split()) - command = ("{} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " "-o {}").format( - cls.ev_fileBcal, cls.lcB + command = ( + f"{cls.ev_fileBcal} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " + f"-o {cls.lcB}" ) hen.lcurve.main(command.split()) - cls.pdsA = os.path.join(cls.datadir, "monol_testA_E3-50_pds" + HEN_FILE_EXTENSION) - cls.pdsB = os.path.join(cls.datadir, "monol_testB_E3-50_pds" + HEN_FILE_EXTENSION) - cls.cpds = os.path.join(cls.datadir, "monol_test_E3-50_cpds" + HEN_FILE_EXTENSION) + cls.pdsA = os.path.join( + cls.datadir, "monol_testA_E3-50_pds" + HEN_FILE_EXTENSION + ) + cls.pdsB = os.path.join( + cls.datadir, "monol_testB_E3-50_pds" + HEN_FILE_EXTENSION + ) + cls.cpds = os.path.join( + cls.datadir, "monol_test_E3-50_cpds" + HEN_FILE_EXTENSION + ) - command = "{} {} -f 128 -k PDS --save-all --norm leahy".format(cls.lcA, cls.lcB) + command = f"{cls.lcA} {cls.lcB} -f 128 -k PDS --save-all --norm leahy" hen.fspec.main(command.split()) - command = "{} {} -f 128 -k CPDS --save-all --norm leahy".format(cls.lcA, cls.lcB) + command = f"{cls.lcA} {cls.lcB} -f 128 -k CPDS --save-all --norm leahy" hen.fspec.main(command.split()) assert os.path.exists(cls.cpds) assert os.path.exists(cls.pdsA) @@ -122,7 +118,7 @@ def setup_class(cls): def test_scripts_are_installed(self): """Test only once that command line scripts are installed correctly.""" fits_file = os.path.join(self.datadir, "monol_testA.evt") - command = "HENreadfile {0}".format(fits_file) + command = f"HENreadfile {fits_file}" sp.check_call(command.split()) def test_get_file_type(self): @@ -175,14 +171,14 @@ def test_save_varen(self, kind, format): def test_colors_fail_uncalibrated(self): """Test light curve using PI filtering.""" - command = ("{0} -b 100 -e {1} {2} {2} {3}").format(self.ev_fileA, 3, 5, 10) + command = f"{self.ev_fileA} -b 100 -e {3} {5} {5} {10}" with pytest.raises(ValueError, match="Energy information not found in file"): hen.colors.main(command.split()) def test_colors(self): """Test light curve using PI filtering.""" # calculate colors - command = ("{0} -b 100 -e {1} {2} {2} {3}").format(self.ev_fileAcal, 3, 5, 10) + command = f"{self.ev_fileAcal} -b 100 -e {3} {5} {5} {10}" hen.colors.main(command.split()) new_filename = os.path.join( @@ -211,7 +207,9 @@ def test_power_colors(self): def test_power_colors_2files(self): """Test light curve using PI filtering.""" # calculate colors - command = f"--cross {self.ev_fileAcal} {self.ev_fileBcal} -s 16 -b -6 -f 1 2 4 8 16 " + command = ( + f"--cross {self.ev_fileAcal} {self.ev_fileBcal} -s 16 -b -6 -f 1 2 4 8 16 " + ) with pytest.warns( UserWarning, match="(Some .non-log.)|(All power spectral)|(Poisson-subtracted)|(cast to real)", @@ -231,7 +229,7 @@ def test_power_colors_2files_raises_no_cross_output(self): def test_readfile_fits(self): """Test reading and dumping a FITS file.""" fitsname = os.path.join(self.datadir, "monol_testA.evt") - command = "{0}".format(fitsname) + command = f"{fitsname}" hen.io.main(command.split()) @@ -271,7 +269,10 @@ def test_plot_hid(self): ) hen.lcurve.main(command.split()) - lname = os.path.join(self.datadir, "monol_testA_nustar_fpma_E3-10_lc") + HEN_FILE_EXTENSION + lname = ( + os.path.join(self.datadir, "monol_testA_nustar_fpma_E3-10_lc") + + HEN_FILE_EXTENSION + ) os.path.exists(lname) cname = ( os.path.join(self.datadir, "monol_testA_nustar_fpma_E_10-5_over_5-3") diff --git a/hendrics/tests/test_base.py b/hendrics/tests/test_base.py index 90c6bcc9..ac54107b 100644 --- a/hendrics/tests/test_base.py +++ b/hendrics/tests/test_base.py @@ -1,10 +1,11 @@ import os -import pytest + import numpy as np -from hendrics.base import deorbit_events, normalize_dyn_profile +import pytest from stingray.events import EventList + +from hendrics.base import deorbit_events, normalize_dyn_profile from hendrics.tests import _dummy_par -from hendrics.fold import HAS_PINT class TestNormalize: @@ -59,7 +60,9 @@ def test_deorbit_badpar(): def test_deorbit_non_existing_par(): ev = np.asarray(1) - with pytest.raises(FileNotFoundError, match="Parameter file warjladsfjqpeifjsdk.par"): + with pytest.raises( + FileNotFoundError, match="Parameter file warjladsfjqpeifjsdk.par" + ): deorbit_events(ev, "warjladsfjqpeifjsdk.par") diff --git a/hendrics/tests/test_binary.py b/hendrics/tests/test_binary.py index 5f02f0f2..3bfe7290 100644 --- a/hendrics/tests/test_binary.py +++ b/hendrics/tests/test_binary.py @@ -7,8 +7,7 @@ import hendrics as hen from hendrics.tests import _dummy_par -from hendrics.fold import HAS_PINT -from hendrics import binary, calibrate, io, lcurve, read_events + from . import cleanup_test_dir HEN_FILE_EXTENSION = hen.io.HEN_FILE_EXTENSION @@ -19,7 +18,7 @@ FileNotFoundError = IOError -class TestBinary(object): +class TestBinary: """Test how command lines work. Usually considered bad practice, but in this @@ -28,55 +27,66 @@ class TestBinary(object): Inspired by https://stackoverflow.com/questions/5387299/python-unittest-testcase-execution-order When command line is missing, uses some function calls - """ # NOQA + """ @classmethod def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileA = os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ) cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) - cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) + cls.ev_fileA = os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ) + cls.ev_fileB = os.path.join( + cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION + ) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, ) cls.par = _dummy_par("bubububu.par") - command = "{0} --discard-calibration".format(os.path.join(cls.datadir, "monol_testA.evt")) + command = "{0} --discard-calibration".format( + os.path.join(cls.datadir, "monol_testA.evt") + ) hen.read_events.main(command.split()) command = "{} -r {}".format( - os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), + os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ), os.path.join(cls.datadir, "test.rmf"), ) hen.calibrate.main(command.split()) cls.lcA = os.path.join( os.path.join(cls.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) ) - command = ("{} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " "-o {}").format( - cls.ev_fileAcal, cls.lcA + command = ( + f"{cls.ev_fileAcal} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " + f"-o {cls.lcA}" ) hen.lcurve.main(command.split()) def test_save_binary_events(self): f = self.ev_fileA with pytest.raises(ValueError, match="Energy filtering requested"): - hen.binary.main_presto("{} -b 0.1 -e 3 59 --debug".format(f).split()) + hen.binary.main_presto(f"{f} -b 0.1 -e 3 59 --debug".split()) @pytest.mark.remote_data @pytest.mark.skipif("not HAS_PINT") def test_save_binary_calibrated_events(self): f = self.ev_fileAcal hen.binary.main_presto( - "{} -b 0.1 -e 3 59 --debug --deorbit-par {}".format(f, self.par).split() + f"{f} -b 0.1 -e 3 59 --debug --deorbit-par {self.par}".split() ) assert os.path.exists(f.replace(HEN_FILE_EXTENSION, ".dat")) assert os.path.exists(f.replace(HEN_FILE_EXTENSION, ".inf")) def test_save_binary_lc(self): f = self.lcA - hen.binary.main_presto("{}".format(f).split()) + hen.binary.main_presto(f"{f}".split()) assert os.path.exists(f.replace(HEN_FILE_EXTENSION, ".dat")) assert os.path.exists(f.replace(HEN_FILE_EXTENSION, ".inf")) diff --git a/hendrics/tests/test_calibrate.py b/hendrics/tests/test_calibrate.py index fdd69d3d..a18e9207 100644 --- a/hendrics/tests/test_calibrate.py +++ b/hendrics/tests/test_calibrate.py @@ -1,11 +1,13 @@ import os + import numpy as np import pytest -from hendrics.calibrate import default_nustar_rmf + import hendrics as hen -from hendrics.tests import _dummy_par -from hendrics import io, lcurve, read_events, fake +from hendrics.calibrate import default_nustar_rmf from hendrics.io import load_events, save_events +from hendrics.tests import _dummy_par + from . import cleanup_test_dir HEN_FILE_EXTENSION = hen.io.HEN_FILE_EXTENSION @@ -23,16 +25,22 @@ def test_default_nustar_rmf(caplog): assert newpath == path_to_rmf -class TestCalibrate(object): +class TestCalibrate: @classmethod def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileA = os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ) cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) - cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) + cls.ev_fileA = os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ) + cls.ev_fileB = os.path.join( + cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION + ) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, @@ -49,8 +57,12 @@ def setup_class(cls): ) hen.read_events.main(command.split()) command = "{} {} -r {} --nproc 2".format( - os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), - os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION), + os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ), + os.path.join( + cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION + ), cls.rmf, ) hen.calibrate.main(command.split()) @@ -72,7 +84,7 @@ def setup_class(cls): cls.xmm_fits_file, ] ) - command = "{0} --discard-calibration".format(cls.xmm_fits_file) + command = f"{cls.xmm_fits_file} --discard-calibration" hen.read_events.main(command.split()) cls.xmm_ev_file = os.path.join( cls.datadir, @@ -94,21 +106,20 @@ def test_calibrate(self): def test_calibrate_xmm_raises(self): """Test event file calibration.""" - command = "{0} -r {1}".format(self.xmm_ev_file, self.rmf) + command = f"{self.xmm_ev_file} -r {self.rmf}" with pytest.raises(RuntimeError, match="Calibration for XMM should work"): hen.calibrate.main(command.split()) def test_calibrate_raises_missing_mission(self): """Test event file calibration.""" - from hendrics.io import load_events, save_events ev = load_events(self.ev_fileB) ev.mission = None bubu_fname = "budidum" + HEN_FILE_EXTENSION save_events(ev, bubu_fname) - command = "{0} --rough".format(bubu_fname) + command = f"{bubu_fname} --rough" with pytest.raises(ValueError): hen.calibrate.main(command.split()) diff --git a/hendrics/tests/test_colors.py b/hendrics/tests/test_colors.py index 902818e7..bab91118 100644 --- a/hendrics/tests/test_colors.py +++ b/hendrics/tests/test_colors.py @@ -1,40 +1,15 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """Test a full run of the codes from the command line.""" -import shutil import os -import glob -import subprocess as sp import numpy as np -from astropy import log -from astropy.logger import AstropyUserWarning import pytest -from stingray.lightcurve import Lightcurve + import hendrics as hen +from astropy import log from hendrics.tests import _dummy_par -from hendrics.fold import HAS_PINT -from hendrics import ( - fake, - fspec, - base, - binary, - calibrate, - colors, - create_gti, - exposure, - exvar, - io, - lcurve, - modeling, - plot, - read_events, - rebin, - save_as_xspec, - timelags, - varenergy, - sum_fspec, -) + from . import cleanup_test_dir try: @@ -48,7 +23,7 @@ # log.basicConfig(filename='HEN.log', level=log.DEBUG, filemode='w') -class TestFullRun(object): +class TestFullRun: """Test how command lines work. Usually considered bad practice, but in this @@ -57,17 +32,23 @@ class TestFullRun(object): Inspired by https://stackoverflow.com/questions/5387299/python-unittest-testcase-execution-order When command line is missing, uses some function calls - """ # NOQA + """ @classmethod def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileA = os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ) cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) - cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) + cls.ev_fileA = os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ) + cls.ev_fileB = os.path.join( + cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION + ) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, @@ -84,8 +65,12 @@ def setup_class(cls): hen.read_events.main(command.split()) command = "{} {} -r {}".format( - os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), - os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION), + os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ), + os.path.join( + cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION + ), os.path.join(cls.datadir, "test.rmf"), ) hen.calibrate.main(command.split()) @@ -94,10 +79,10 @@ def setup_class(cls): os.path.join(cls.datadir, "monol_testA_E3-10_lc" + HEN_FILE_EXTENSION) ) - command = ("{} -e 3 10 -b 100 " "-o {}").format(cls.ev_fileAcal, cls.lc3_10) + command = f"{cls.ev_fileAcal} -e 3 10 -b 100 " f"-o {cls.lc3_10}" hen.lcurve.main(command.split()) - command = ("{0} -b 100 -e {1} {2} {2} {3}").format(cls.ev_fileAcal, 3, 5, 10) + command = f"{cls.ev_fileAcal} -b 100 -e {3} {5} {5} {10}" hen.colors.main(command.split()) cls.colorfile = os.path.join( @@ -116,7 +101,7 @@ def test_colors_correct_gti(self): def test_colors_fail_uncalibrated(self): """Test light curve using PI filtering.""" - command = ("{0} -b 100 -e {1} {2} {2} {3}").format(self.ev_fileA, 3, 5, 10) + command = f"{self.ev_fileA} -b 100 -e {3} {5} {5} {10}" with pytest.raises(ValueError, match="Energy information not found in file"): hen.colors.main(command.split()) @@ -140,7 +125,7 @@ def test_plot_color(self): def test_plot_hid(self): """Test plotting with linear axes.""" # also produce a light curve with the same binning - command = ("{0} -b 100 --energy-interval {1} {2}").format(self.ev_fileAcal, 3, 10) + command = f"{self.ev_fileAcal} -b 100 --energy-interval {3} {10}" hen.lcurve.main(command.split()) lname = self.lc3_10 diff --git a/hendrics/tests/test_efsearch.py b/hendrics/tests/test_efsearch.py index 6484c96d..ea6ba0fb 100644 --- a/hendrics/tests/test_efsearch.py +++ b/hendrics/tests/test_efsearch.py @@ -1,28 +1,39 @@ -import os import copy -import glob +import os from collections.abc import Iterable +import numpy as np import pytest -from stingray.lightcurve import Lightcurve from stingray.events import EventList -import numpy as np +from stingray.lightcurve import Lightcurve + +from hendrics.base import hen_root +from hendrics.efsearch import ( + decide_binary_parameters, + folding_orbital_search, + main_accelsearch, + main_efsearch, + main_z2vspf, + main_zsearch, +) +from hendrics.fold import ( + fit_profile_with_sinusoids, + get_TOAs_from_events, + main_deorbit, + main_fold, + std_fold_fit_func, +) from hendrics.io import ( - save_events, HEN_FILE_EXTENSION, - load_folding, - load_events, get_file_type, + load_events, + load_folding, + save_events, save_lcurve, ) -from hendrics.efsearch import main_efsearch, main_zsearch -from hendrics.efsearch import main_accelsearch, main_z2vspf -from hendrics.efsearch import decide_binary_parameters, folding_orbital_search -from hendrics.fold import main_fold, main_deorbit, std_fold_fit_func -from hendrics.fold import fit_profile_with_sinusoids, get_TOAs_from_events from hendrics.plot import plot_folding from hendrics.tests import _dummy_par -from hendrics.base import hen_root + from . import cleanup_test_dir try: @@ -32,9 +43,6 @@ except ImportError: HAS_PD = False -from hendrics.fold import HAS_PINT -from hendrics.efsearch import HAS_IMAGEIO - class TestEFsearch: def setup_class(cls): @@ -67,7 +75,9 @@ def setup_class(cls): cls.dum_scramble = "events_scramble" + HEN_FILE_EXTENSION save_events(events, cls.dum) events_scramble = copy.deepcopy(events) - events_scramble.time = np.sort(np.random.uniform(cls.tstart, cls.tend, events.time.size)) + events_scramble.time = np.sort( + np.random.uniform(cls.tstart, cls.tend, events.time.size) + ) save_events(events_scramble, cls.dum_scramble) cls.par = "bububububu.par" _dummy_par(cls.par) @@ -121,7 +131,9 @@ def test_get_TOAs_template(self): def test_fit_profile_with_sinusoids(self): nbin = 32 phases = np.arange(0, 1, 1 / nbin) - prof_smooth = np.cos(2 * np.pi * phases) + 0.5 * np.cos(4 * np.pi * (phases + 0.5)) + prof_smooth = np.cos(2 * np.pi * phases) + 0.5 * np.cos( + 4 * np.pi * (phases + 0.5) + ) prof_smooth = (prof_smooth + 5) * 64 prof = np.random.poisson(prof_smooth) baseline = np.mean(prof) @@ -571,7 +583,9 @@ def test_zsearch_fdots_ffa(self): def test_fold_fast_fails(self): evfile = self.dum - with pytest.raises(ValueError, match="The fast option is only available for z "): + with pytest.raises( + ValueError, match="The fast option is only available for z " + ): main_efsearch([evfile, "-f", "9.85", "-F", "9.95", "-n", "64", "--fast"]) def test_zsearch_fdots_fast_transient(self): @@ -712,7 +726,9 @@ def test_accelsearch(self): def test_accelsearch_nodetections(self): evfile = self.dum_scramble with pytest.warns(UserWarning, match="The accelsearch functionality"): - outfile = main_accelsearch([evfile, "--fmin", "1", "--fmax", "1.1", "--zmax", "1"]) + outfile = main_accelsearch( + [evfile, "--fmin", "1", "--fmax", "1.1", "--zmax", "1"] + ) assert os.path.exists(outfile) os.unlink(outfile) diff --git a/hendrics/tests/test_exposure.py b/hendrics/tests/test_exposure.py index 61c55881..727f778a 100644 --- a/hendrics/tests/test_exposure.py +++ b/hendrics/tests/test_exposure.py @@ -1,4 +1,5 @@ import numpy as np + from hendrics import exposure diff --git a/hendrics/tests/test_fake.py b/hendrics/tests/test_fake.py index c31287f5..8bea27ab 100644 --- a/hendrics/tests/test_fake.py +++ b/hendrics/tests/test_fake.py @@ -1,21 +1,19 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """Test a full run of the codes from the command line.""" -import shutil import os -import glob -import subprocess as sp -import pytest + import numpy as np +import pytest +from stingray.events import EventList + +import hendrics as hen from astropy import log from astropy.io import fits -import hendrics as hen -from stingray.events import EventList -from hendrics.tests import _dummy_par -from hendrics import fake, calibrate, read_events, io from hendrics.fake import scramble from hendrics.io import load_events -from hendrics.fold import HAS_PINT +from hendrics.tests import _dummy_par + from . import cleanup_test_dir try: @@ -34,7 +32,7 @@ def test_filter_for_deadtime_nonpar(): events = np.array([1, 1.05, 1.07, 1.08, 1.1, 2, 2.2, 3, 3.1, 3.2]) filt_events = hen.fake.filter_for_deadtime(events, 0.11) expected = np.array([1, 2, 2.2, 3, 3.2]) - assert np.all(filt_events == expected), "Wrong: {} vs {}".format(filt_events, expected) + assert np.all(filt_events == expected), f"Wrong: {filt_events} vs {expected}" def test_filter_for_deadtime_nonpar_bkg(): @@ -46,15 +44,16 @@ def test_filter_for_deadtime_nonpar_bkg(): ) expected_ev = np.array([2, 2.2, 3, 3.2]) expected_bk = np.array([1]) - assert np.all(filt_events == expected_ev), "Wrong: {} vs {}".format(filt_events, expected_ev) - assert np.all(info.bkg == expected_bk), "Wrong: {} vs {}".format(info.bkg, expected_bk) + assert np.all(filt_events == expected_ev), f"Wrong: {filt_events} vs {expected_ev}" + assert np.all(info.bkg == expected_bk), f"Wrong: {info.bkg} vs {expected_bk}" def test_filter_for_deadtime_par(): """Test dead time filter, paralyzable case.""" events = np.array([1, 1.1, 2, 2.2, 3, 3.1, 3.2]) assert np.all( - hen.fake.filter_for_deadtime(events, 0.11, paralyzable=True) == np.array([1, 2, 2.2, 3]) + hen.fake.filter_for_deadtime(events, 0.11, paralyzable=True) + == np.array([1, 2, 2.2, 3]) ) @@ -71,8 +70,8 @@ def test_filter_for_deadtime_par_bkg(): ) expected_ev = np.array([2, 2.2, 3]) expected_bk = np.array([1]) - assert np.all(filt_events == expected_ev), "Wrong: {} vs {}".format(filt_events, expected_ev) - assert np.all(info.bkg == expected_bk), "Wrong: {} vs {}".format(info.bkg, expected_bk) + assert np.all(filt_events == expected_ev), f"Wrong: {filt_events} vs {expected_ev}" + assert np.all(info.bkg == expected_bk), f"Wrong: {info.bkg} vs {expected_bk}" def test_filter_for_deadtime_par_bkg_obj(): @@ -97,10 +96,10 @@ def test_filter_for_deadtime_par_bkg_obj(): filt_pis = filt_events.pi filt_nrgs = filt_events.energy - assert np.all(filt_times == expected_ev), "Wrong: {} vs {}".format(filt_events, expected_ev) - assert np.all(filt_pis == expected_pi), "Wrong: {} vs {}".format(filt_events, expected_ev) - assert np.all(filt_nrgs == expected_nrg), "Wrong: {} vs {}".format(filt_events, expected_ev) - assert np.all(info.bkg == expected_bk), "Wrong: {} vs {}".format(info.bkg, expected_bk) + assert np.all(filt_times == expected_ev), f"Wrong: {filt_events} vs {expected_ev}" + assert np.all(filt_pis == expected_pi), f"Wrong: {filt_events} vs {expected_ev}" + assert np.all(filt_nrgs == expected_nrg), f"Wrong: {filt_events} vs {expected_ev}" + assert np.all(info.bkg == expected_bk), f"Wrong: {info.bkg} vs {expected_bk}" def test_deadtime_mask_par(): @@ -134,7 +133,7 @@ def verify_all_checksums(filename): assert hdu.verify_checksum() == 1, f"Bad checksum: {hdu.name}" -class TestFake(object): +class TestFake: """Test how command lines work. Usually considered bad practice, but in this @@ -143,7 +142,7 @@ class TestFake(object): Inspired by https://stackoverflow.com/questions/5387299/python-unittest-testcase-execution-order When command line is missing, uses some function calls - """ # NOQA + """ @classmethod def setup_class(cls): @@ -154,11 +153,13 @@ def setup_class(cls): ) cls.par = _dummy_par("bubububu.par") cls.fits_fileA = os.path.join(cls.datadir, "monol_testA.evt") - command = "{0} --discard-calibration".format(cls.fits_fileA) + command = f"{cls.fits_fileA} --discard-calibration" hen.read_events.main(command.split()) cls.first_event_file_cal = "calibrated" + HEN_FILE_EXTENSION - hen.calibrate.calibrate(cls.first_event_file, cls.first_event_file_cal, rough=True) + hen.calibrate.calibrate( + cls.first_event_file, cls.first_event_file_cal, rough=True + ) cls.xmm_fits_file = os.path.join(cls.datadir, "monol_test_fake_lc_xmm.evt") # Note that I don't specify the instrument. This is because @@ -178,7 +179,7 @@ def setup_class(cls): cls.xmm_fits_file, ] ) - command = "{0} --discard-calibration".format(cls.xmm_fits_file) + command = f"{cls.xmm_fits_file} --discard-calibration" hen.read_events.main(command.split()) cls.xmm_ev_file = os.path.join( cls.datadir, @@ -298,7 +299,9 @@ def test_scramble_events(self): # Put exactly one photon inside a very short GTI times[0] = 0.5 times = np.sort(times) - event_list = EventList(times, gti=np.array([[0, 0.9], [111, 123.2], [125.123, 1000]])) + event_list = EventList( + times, gti=np.array([[0, 0.9], [111, 123.2], [125.123, 1000]]) + ) new_event_list = scramble(event_list, "smooth") assert new_event_list.time.size == times.size @@ -311,14 +314,16 @@ def test_scramble_events(self): def test_calibrate_xmm(self): """Test event file calibration.""" xmm_file = self.xmm_ev_file - command = "{0} -r {1} --nproc 2".format(xmm_file, os.path.join(self.datadir, "test.rmf")) + command = "{0} -r {1} --nproc 2".format( + xmm_file, os.path.join(self.datadir, "test.rmf") + ) with pytest.raises(RuntimeError): hen.calibrate.main(command.split()) def test_calibrate_xmm_normf(self): """Test event file calibration.""" xmm_file = self.xmm_ev_file - command = "{0} --rough --nproc 2".format(xmm_file) + command = f"{xmm_file} --rough --nproc 2" hen.calibrate.main(command.split()) @classmethod diff --git a/hendrics/tests/test_ffa.py b/hendrics/tests/test_ffa.py index a1d83f7a..a83d01f1 100644 --- a/hendrics/tests/test_ffa.py +++ b/hendrics/tests/test_ffa.py @@ -1,11 +1,9 @@ +import numpy as np from stingray.events import EventList from stingray.lightcurve import Lightcurve -import numpy as np -from hendrics.base import HAS_NUMBA -from ..ffa import ffa_search from ..efsearch import fit -import pytest +from ..ffa import ffa_search # @pytest.mark.skipif('not HAS_NUMBA') @@ -59,10 +57,12 @@ def test_ffa_large_intv(): def test_ffa_vs_folding_search(): import time - from hendrics.efsearch import folding_search + from stingray.events import EventList from stingray.lightcurve import Lightcurve + from hendrics.efsearch import folding_search + period = 0.01 pmin = 0.0095 pmax = 0.0105 @@ -81,11 +81,11 @@ def test_ffa_vs_folding_search(): t0 = time.time() per, st = ffa_search(lc.counts, dt, pmin, pmax) t1 = time.time() - print("FFA completed in {:.1e} s".format(t1 - t0)) + print(f"FFA completed in {t1 - t0:.1e} s") t1 = time.time() freqs, stats, _, _ = folding_search(ev, 1 / pmax, 1 / pmin, oversample=3, nbin=128) t2 = time.time() - print("Standard search completed in {:.1e} s".format(t2 - t1)) + print(f"Standard search completed in {t2 - t1:.1e} s") comparable_stats = np.array([st[idx] for idx in np.searchsorted(per, 1 / freqs)]) assert (comparable_stats - stats + 127).std() < 127 diff --git a/hendrics/tests/test_fspec.py b/hendrics/tests/test_fspec.py index 84dd90a1..ee0689b0 100644 --- a/hendrics/tests/test_fspec.py +++ b/hendrics/tests/test_fspec.py @@ -1,7 +1,5 @@ -import shutil import os -import glob -import subprocess as sp +import shutil import numpy as np @@ -11,29 +9,19 @@ except ImportError: from numpy import ComplexWarning -import stingray -from astropy import log import pytest +import stingray from stingray.events import EventList + import hendrics as hen -from hendrics.tests import _dummy_par +from astropy import log from hendrics import ( - calibrate, - colors, io, - lcurve, - modeling, - plot, - read_events, - rebin, - save_as_xspec, - sum_fspec, - timelags, - varenergy, ) - -from hendrics.base import touch, HENDRICS_STAR_VALUE +from hendrics.base import HENDRICS_STAR_VALUE, touch from hendrics.fspec import calc_cpds, calc_pds +from hendrics.tests import _dummy_par + from . import cleanup_test_dir try: @@ -62,7 +50,9 @@ def test_cpds_fails_noclobber_exists(): def test_distributed_pds(): - events = EventList(np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]])) + events = EventList( + np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]]) + ) if hasattr(stingray.AveragedPowerspectrum, "from_events"): single_periodogram = stingray.AveragedPowerspectrum( events, @@ -86,8 +76,12 @@ def test_distributed_pds(): def test_distributed_cpds(): - events1 = EventList(np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]])) - events2 = EventList(np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]])) + events1 = EventList( + np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]]) + ) + events2 = EventList( + np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]]) + ) if hasattr(stingray.AveragedCrossspectrum, "from_events"): single_periodogram = stingray.AveragedCrossspectrum( events1, @@ -102,14 +96,16 @@ def test_distributed_cpds(): events1, events2, segment_size=100, dt=0.1, norm="leahy" ) - pds_iterable = hen.fspec._provide_cross_periodograms(events1, events2, 100, 0.1, "leahy") + pds_iterable = hen.fspec._provide_cross_periodograms( + events1, events2, 100, 0.1, "leahy" + ) pds_distr = hen.fspec.average_periodograms(pds_iterable) assert np.allclose(pds_distr.power, single_periodogram.power) assert np.allclose(pds_distr.freq, single_periodogram.freq) assert pds_distr.m == single_periodogram.m -class TestFullRun(object): +class TestFullRun: """Test how command lines work. Usually considered bad practice, but in this @@ -118,7 +114,7 @@ class TestFullRun(object): Inspired by https://stackoverflow.com/questions/5387299/python-unittest-testcase-execution-order When command line is missing, uses some function calls - """ # NOQA + """ @classmethod def setup_class(cls): @@ -127,8 +123,12 @@ def setup_class(cls): cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) - cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) + cls.ev_fileA = os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ) + cls.ev_fileB = os.path.join( + cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION + ) for fname in [cls.ev_fileA, cls.ev_fileB]: if os.path.exists(fname): os.unlink(fname) @@ -140,7 +140,7 @@ def setup_class(cls): ) hen.read_events.main(command.split()) - command = "{0} {1} --nproc 2 -b -1".format(cls.ev_fileA, cls.ev_fileB) + command = f"{cls.ev_fileA} {cls.ev_fileB} --nproc 2 -b -1" hen.lcurve.main(command.split()) cls.lcA = cls.ev_fileA.replace("_ev", "_lc") cls.lcB = cls.ev_fileB.replace("_ev", "_lc") @@ -158,14 +158,10 @@ def setup_class(cls): "monol_test_nustar_fpm_3-50keV_cpds" + HEN_FILE_EXTENSION, ) - command = "{} {} -f 128 -k PDS --save-all --norm leahy --emin 3 --emax 50".format( - cls.ev_fileA, cls.ev_fileB - ) + command = f"{cls.ev_fileA} {cls.ev_fileB} -f 128 -k PDS --save-all --norm leahy --emin 3 --emax 50" hen.fspec.main(command.split()) - command = "{} {} -f 128 -k CPDS --save-all --norm leahy --emin 3 --emax 50".format( - cls.ev_fileA, cls.ev_fileB - ) + command = f"{cls.ev_fileA} {cls.ev_fileB} -f 128 -k CPDS --save-all --norm leahy --emin 3 --emax 50" hen.fspec.main(command.split()) for pds in [pdsA, pdsB, cpds]: @@ -175,12 +171,13 @@ def test_pds_leahy_emax_only(self): """Test PDS production.""" evdata = self.ev_fileA - command = "{0} -f 128 -k PDS --save-all --norm leahy -b {1} --emax 50".format(evdata, 1) + command = f"{evdata} -f 128 -k PDS --save-all --norm leahy -b {1} --emax 50" hen.fspec.main(command.split()) out = os.path.join( self.datadir, - f"monol_testA_nustar_fpma_{HENDRICS_STAR_VALUE}-50keV_pds" + HEN_FILE_EXTENSION, + f"monol_testA_nustar_fpma_{HENDRICS_STAR_VALUE}-50keV_pds" + + HEN_FILE_EXTENSION, ) assert os.path.exists(out) io.remove_pds(out) @@ -189,12 +186,13 @@ def test_pds_leahy_emin_only(self): """Test PDS production.""" evdata = self.ev_fileA - command = "{0} -f 128 -k PDS --save-all --norm leahy -b {1} --emin 3".format(evdata, 1) + command = f"{evdata} -f 128 -k PDS --save-all --norm leahy -b {1} --emin 3" hen.fspec.main(command.split()) out = os.path.join( self.datadir, - f"monol_testA_nustar_fpma_3-{HENDRICS_STAR_VALUE}keV_pds" + HEN_FILE_EXTENSION, + f"monol_testA_nustar_fpma_3-{HENDRICS_STAR_VALUE}keV_pds" + + HEN_FILE_EXTENSION, ) assert os.path.exists(out) io.remove_pds(out) @@ -204,14 +202,14 @@ def test_pds_leahy(self): evdata = self.ev_fileA lcdata = self.lcA - command = "{0} -f 128. -k PDS --norm leahy -b -1".format(evdata) + command = f"{evdata} -f 128. -k PDS --norm leahy -b -1" hen.fspec.main(command.split()) evout = evdata.replace("_ev", "_pds") assert os.path.exists(evout) evpds = hen.io.load_pds(evout) io.remove_pds(evout) - command = "{0} -f 128. -k PDS --save-all --norm leahy".format(lcdata) + command = f"{lcdata} -f 128. -k PDS --save-all --norm leahy" hen.fspec.main(command.split()) lcout = lcdata.replace("_lc", "_pds") assert os.path.exists(lcout) @@ -225,14 +223,14 @@ def test_pds_leahy_lombscargle(self): evdata = self.ev_fileA lcdata = self.lcA - command = "{0} -k PDS --norm leahy --lombscargle -b -1".format(evdata) + command = f"{evdata} -k PDS --norm leahy --lombscargle -b -1" hen.fspec.main(command.split()) evout = evdata.replace("_ev", "_LS_pds") assert os.path.exists(evout) evpds = hen.io.load_pds(evout) io.remove_pds(evout) - command = "{0} -k PDS --norm leahy --lombscargle".format(lcdata) + command = f"{lcdata} -k PDS --norm leahy --lombscargle" hen.fspec.main(command.split()) lcout = lcdata.replace("_lc", "_LS_pds") assert os.path.exists(lcout) @@ -248,7 +246,11 @@ def test_cpds_leahy_lombscargle(self): command = f"{evdata1} {evdata2} -k CPDS --norm leahy --lombscargle -b -1" hen.fspec.main(command.split()) - evout = evdata1.replace("fpma", "fpm").replace("testA", "test").replace("_ev", "_LS_cpds") + evout = ( + evdata1.replace("fpma", "fpm") + .replace("testA", "test") + .replace("_ev", "_LS_cpds") + ) assert os.path.exists(evout) evpds = hen.io.load_pds(evout) io.remove_pds(evout) @@ -259,14 +261,14 @@ def test_pds_save_nothing(self): evout = evdata.replace("_ev", "_pds") lcout = lcdata.replace("_lc", "_pds") - command = "{0} -f 128 -k PDS --norm leahy --no-auxil -b 0.5".format(evdata) + command = f"{evdata} -f 128 -k PDS --norm leahy --no-auxil -b 0.5" hen.fspec.main(command.split()) assert os.path.exists(evout) evpds = hen.io.load_pds(evout) assert not os.path.exists(evout.replace(HEN_FILE_EXTENSION, "")) io.remove_pds(evout) - command = "{0} -f 128 -k PDS --norm leahy --no-auxil ".format(lcdata) + command = f"{lcdata} -f 128 -k PDS --norm leahy --no-auxil " hen.fspec.main(command.split()) assert os.path.exists(lcout) lcpds = hen.io.load_pds(lcout) @@ -285,8 +287,12 @@ def test_pds(self, data_kind, lombscargle): else: label = "_lc" - outA = os.path.join(self.datadir, f"monol_testA_nustar_fpma_pds" + HEN_FILE_EXTENSION) - outB = os.path.join(self.datadir, f"monol_testB_nustar_fpmb_pds" + HEN_FILE_EXTENSION) + outA = os.path.join( + self.datadir, "monol_testA_nustar_fpma_pds" + HEN_FILE_EXTENSION + ) + outB = os.path.join( + self.datadir, "monol_testB_nustar_fpmb_pds" + HEN_FILE_EXTENSION + ) if lombscargle: outA = outA.replace("pds", "LS_pds") outB = outB.replace("pds", "LS_pds") @@ -300,8 +306,10 @@ def test_pds(self, data_kind, lombscargle): opts += " --lombscargle" command = "{0} {1} {2}".format( opts, - os.path.join(self.datadir, f"monol_testA_nustar_fpma{label}") + HEN_FILE_EXTENSION, - os.path.join(self.datadir, f"monol_testB_nustar_fpmb{label}") + HEN_FILE_EXTENSION, + os.path.join(self.datadir, f"monol_testA_nustar_fpma{label}") + + HEN_FILE_EXTENSION, + os.path.join(self.datadir, f"monol_testB_nustar_fpmb{label}") + + HEN_FILE_EXTENSION, ) hen.fspec.main(command.split()) @@ -330,12 +338,18 @@ def test_ignore_gti(self, data_kind): label = "_lc" command = "{0} {1} -f 128 --ignore-gtis".format( - os.path.join(self.datadir, f"monol_testA_nustar_fpma{label}") + HEN_FILE_EXTENSION, - os.path.join(self.datadir, f"monol_testB_nustar_fpmb{label}") + HEN_FILE_EXTENSION, + os.path.join(self.datadir, f"monol_testA_nustar_fpma{label}") + + HEN_FILE_EXTENSION, + os.path.join(self.datadir, f"monol_testB_nustar_fpmb{label}") + + HEN_FILE_EXTENSION, ) hen.fspec.main(command.split()) - outA = os.path.join(self.datadir, f"monol_testA_nustar_fpma_pds" + HEN_FILE_EXTENSION) - outB = os.path.join(self.datadir, f"monol_testB_nustar_fpmb_pds" + HEN_FILE_EXTENSION) + outA = os.path.join( + self.datadir, "monol_testA_nustar_fpma_pds" + HEN_FILE_EXTENSION + ) + outB = os.path.join( + self.datadir, "monol_testB_nustar_fpmb_pds" + HEN_FILE_EXTENSION + ) assert os.path.exists(outA) assert os.path.exists(outB) os.unlink(outA) @@ -369,10 +383,12 @@ def test_cpds_ignore_instr(self): def test_cpds_rms_norm(self): """Test CPDS production.""" - command = "{0} {1} -f 128 --save-dyn -k CPDS --save-all " "--norm rms -o {2}".format( - self.lcA, - self.lcB, - os.path.join(self.datadir, "monol_test_3-50keV_rms"), + command = ( + "{0} {1} -f 128 --save-dyn -k CPDS --save-all " "--norm rms -o {2}".format( + self.lcA, + self.lcB, + os.path.join(self.datadir, "monol_test_3-50keV_rms"), + ) ) hen.fspec.main(command.split()) @@ -389,10 +405,12 @@ def test_cpds_wrong_norm(self): def test_cpds_dtbig(self): """Test CPDS production.""" - command = "{0} {1} -f 128 --save-dyn -k CPDS --save-all --norm " "frac -o {2}".format( - self.lcA, - self.lcB, - os.path.join(self.datadir, "monol_test_3-50keV_dtb"), + command = ( + "{0} {1} -f 128 --save-dyn -k CPDS --save-all --norm " "frac -o {2}".format( + self.lcA, + self.lcB, + os.path.join(self.datadir, "monol_test_3-50keV_dtb"), + ) ) command += " -b 1" hen.fspec.main(command.split()) @@ -423,7 +441,9 @@ def test_sumpds(self): def test_dumpdyncpds(self): """Test dump dynamical PDSs.""" command = ( - "--noplot " + os.path.join(self.datadir, "monol_test_3-50keV_cpds") + HEN_FILE_EXTENSION + "--noplot " + + os.path.join(self.datadir, "monol_test_3-50keV_cpds") + + HEN_FILE_EXTENSION ) with pytest.raises(NotImplementedError): hen.fspec.dumpdyn_main(command.split()) @@ -431,7 +451,8 @@ def test_dumpdyncpds(self): def test_rebinpds(self): """Test PDS rebinning 1.""" command = "{0} -r 2".format( - os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds") + HEN_FILE_EXTENSION + os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds") + + HEN_FILE_EXTENSION ) hen.rebin.main(command.split()) os.path.exists( @@ -444,8 +465,10 @@ def test_rebinpds(self): def test_rebinpds_geom(self): """Test geometrical PDS rebinning.""" command = "{0} {1} -r 1.03".format( - os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds") + HEN_FILE_EXTENSION, - os.path.join(self.datadir, "monol_testB_nustar_fpmb_3-50keV_pds") + HEN_FILE_EXTENSION, + os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds") + + HEN_FILE_EXTENSION, + os.path.join(self.datadir, "monol_testB_nustar_fpmb_3-50keV_pds") + + HEN_FILE_EXTENSION, ) hen.rebin.main(command.split()) os.path.exists( @@ -464,7 +487,8 @@ def test_rebinpds_geom(self): def test_rebincpds(self): """Test CPDS rebinning.""" command = "{0} -r 2".format( - os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") + HEN_FILE_EXTENSION + os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") + + HEN_FILE_EXTENSION ) hen.rebin.main(command.split()) os.path.exists( @@ -477,7 +501,8 @@ def test_rebincpds(self): def test_rebincpds_geom(self): """Test CPDS geometrical rebinning.""" command = "{0} -r 1.03".format( - os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") + HEN_FILE_EXTENSION + os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") + + HEN_FILE_EXTENSION ) hen.rebin.main(command.split()) os.path.exists( @@ -513,11 +538,15 @@ def test_fit_pds(self): "monol_testB_nustar_fpmb_3-50keV_pds" + HEN_FILE_EXTENSION, ) - command = "{0} {1} -m {2} --frequency-interval 0 10".format(pdsfile1, pdsfile2, modelfile) + command = f"{pdsfile1} {pdsfile2} -m {modelfile} --frequency-interval 0 10" hen.modeling.main_model(command.split()) - out0 = os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds_bestfit.p") - out1 = os.path.join(self.datadir, "monol_testB_nustar_fpmb_3-50keV_pds_bestfit.p") + out0 = os.path.join( + self.datadir, "monol_testA_nustar_fpma_3-50keV_pds_bestfit.p" + ) + out1 = os.path.join( + self.datadir, "monol_testB_nustar_fpmb_3-50keV_pds_bestfit.p" + ) assert os.path.exists(out0) assert os.path.exists(out1) m, k, c = hen.io.load_model( @@ -553,12 +582,14 @@ def test_fit_cpds(self): "monol_test_nustar_fpm_3-50keV_cpds" + HEN_FILE_EXTENSION, ) - command = "{0} -m {1} --frequency-interval 0 10".format(pdsfile1, modelfile) + command = f"{pdsfile1} -m {modelfile} --frequency-interval 0 10" with pytest.warns(ComplexWarning): hen.modeling.main_model(command.split()) - out0 = os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds_bestfit.p") + out0 = os.path.join( + self.datadir, "monol_test_nustar_fpm_3-50keV_cpds_bestfit.p" + ) assert os.path.exists(out0) m, k, c = hen.io.load_model(out0) assert hasattr(m, "amplitude") @@ -589,7 +620,7 @@ def test_fit_pds_f_no_of_intervals_invalid(self): "monol_testB_nustar_fpmb_3-50keV_pds" + HEN_FILE_EXTENSION, ) - command = "{0} {1} -m {2} --frequency-interval 0 1 9".format(pdsfile1, pdsfile2, modelfile) + command = f"{pdsfile1} {pdsfile2} -m {modelfile} --frequency-interval 0 1 9" with pytest.raises(ValueError, match="Invalid number of frequencies specified"): hen.modeling.main_model(command.split()) @@ -600,7 +631,9 @@ def test_savexspec(self): + HEN_FILE_EXTENSION ) hen.save_as_xspec.main(command.split()) - os.path.exists(os.path.join(self.datadir, "monol_testA_nustar_fpmb_3-50keV_pds_rebin2.pha")) + os.path.exists( + os.path.join(self.datadir, "monol_testA_nustar_fpmb_3-50keV_pds_rebin2.pha") + ) def test_savexspec_geom(self): """Test save as Xspec 2.""" @@ -633,7 +666,10 @@ def test_plot_lin(self): os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds_fit") + HEN_FILE_EXTENSION ) - lname = os.path.join(self.datadir, "monol_testA_nustar_fpma_lc") + HEN_FILE_EXTENSION + lname = ( + os.path.join(self.datadir, "monol_testA_nustar_fpma_lc") + + HEN_FILE_EXTENSION + ) hen.plot.main( [ pname, diff --git a/hendrics/tests/test_gti.py b/hendrics/tests/test_gti.py index 0f4d3a6d..cd5db1c3 100644 --- a/hendrics/tests/test_gti.py +++ b/hendrics/tests/test_gti.py @@ -1,14 +1,12 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """Test a full run of the codes from the command line.""" -import shutil import os -import glob -from astropy import log import hendrics as hen +from astropy import log from hendrics.tests import _dummy_par -from hendrics import calibrate, create_gti, io, lcurve, read_events + from . import cleanup_test_dir try: @@ -22,7 +20,7 @@ # log.basicConfig(filename='HEN.log', level=log.DEBUG, filemode='w') -class TestFullRun(object): +class TestFullRun: """Test how command lines work. Usually considered bad practice, but in this @@ -31,17 +29,23 @@ class TestFullRun(object): Inspired by https://stackoverflow.com/questions/5387299/python-unittest-testcase-execution-order When command line is missing, uses some function calls - """ # NOQA + """ @classmethod def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileA = os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ) cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) - cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) + cls.ev_fileA = os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ) + cls.ev_fileB = os.path.join( + cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION + ) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, @@ -60,16 +64,23 @@ def setup_class(cls): cls.ev_fileA, cls.ev_fileB, os.path.join(cls.datadir, "test.rmf") ) hen.calibrate.main(command.split()) - cls.lcA = os.path.join(os.path.join(cls.datadir, "monol_testA_lc" + HEN_FILE_EXTENSION)) - cls.lcB = os.path.join(os.path.join(cls.datadir, "monol_testB_lc" + HEN_FILE_EXTENSION)) - command = ("{} --nproc 2 -b 2 " "-o {}").format(cls.ev_fileAcal, cls.lcA) + cls.lcA = os.path.join( + os.path.join(cls.datadir, "monol_testA_lc" + HEN_FILE_EXTENSION) + ) + cls.lcB = os.path.join( + os.path.join(cls.datadir, "monol_testB_lc" + HEN_FILE_EXTENSION) + ) + command = f"{cls.ev_fileAcal} --nproc 2 -b 2 " f"-o {cls.lcA}" hen.lcurve.main(command.split()) - command = ("{} --nproc 2 -b 2 " "-o {}").format(cls.ev_fileBcal, cls.lcB) + command = f"{cls.ev_fileBcal} --nproc 2 -b 2 " f"-o {cls.lcB}" hen.lcurve.main(command.split()) - command = "{0} -f time>0 -c --debug".format(cls.ev_fileA) + command = f"{cls.ev_fileA} -f time>0 -c --debug" hen.create_gti.main(command.split()) - cls.gtifile = os.path.join(cls.datadir, "monol_testA_nustar_fpma_gti") + HEN_FILE_EXTENSION + cls.gtifile = ( + os.path.join(cls.datadir, "monol_testA_nustar_fpma_gti") + + HEN_FILE_EXTENSION + ) def test_create_gti(self): """Test creating a GTI file.""" @@ -79,28 +90,30 @@ def test_apply_gti(self): """Test applying a GTI file.""" fname = self.gtifile lcfname = self.ev_fileA - lcoutname = self.ev_fileA.replace(HEN_FILE_EXTENSION, "_gtifilt" + HEN_FILE_EXTENSION) - command = "{0} -a {1} --debug".format(lcfname, fname) + lcoutname = self.ev_fileA.replace( + HEN_FILE_EXTENSION, "_gtifilt" + HEN_FILE_EXTENSION + ) + command = f"{lcfname} -a {fname} --debug" hen.create_gti.main(command.split()) hen.io.load_events(lcoutname) def test_create_gti_and_minlen(self): """Test creating a GTI file and apply minimum length.""" fname = self.lcA - command = "{0} -f counts>0 -c -l 10 --debug".format(fname) + command = f"{fname} -f counts>0 -c -l 10 --debug" hen.create_gti.main(command.split()) def test_create_gti_and_apply(self): """Test applying a GTI file and apply minimum length.""" fname = self.gtifile lcfname = self.lcA - command = "{0} -a {1} -l 10 --debug".format(lcfname, fname) + command = f"{lcfname} -a {fname} -l 10 --debug" hen.create_gti.main(command.split()) def test_readfile(self): """Test reading and dumping a HENDRICS file.""" fname = self.gtifile - command = "{0}".format(fname) + command = f"{fname}" hen.io.main(command.split()) diff --git a/hendrics/tests/test_io.py b/hendrics/tests/test_io.py index 85d4e711..d06e710e 100644 --- a/hendrics/tests/test_io.py +++ b/hendrics/tests/test_io.py @@ -1,39 +1,50 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst -from astropy.io.fits import Header +import os + +import numpy as np +import pytest from stingray import ( - StingrayTimeseries, + AveragedCrossspectrum, + Crossspectrum, EventList, Lightcurve, Powerspectrum, - Crossspectrum, - AveragedCrossspectrum, + StingrayTimeseries, ) - -import numpy as np -import os +from astropy.io.fits import Header +from astropy.modeling import models +from astropy.modeling.core import Model from hendrics.base import hen_root -from hendrics.io import load_events, save_events, save_lcurve, load_lcurve from hendrics.io import ( - save_data, + HAS_H5PY, + HEN_FILE_EXTENSION, + _split_high_precision_number, + find_file_in_allowed_paths, + get_file_type, load_data, - save_pds, + load_events, + load_lcurve, + load_model, load_pds, - save_timeseries, load_timeseries, + main, + main_filter_events, + read_header_key, + ref_mjd, + remove_pds, + save_as_ascii, + save_as_qdp, + save_data, + save_events, + save_lcurve, + save_model, + save_pds, + save_timeseries, ) -from hendrics.io import HEN_FILE_EXTENSION, _split_high_precision_number -from hendrics.io import save_model, load_model, HAS_C256, HAS_NETCDF, HAS_H5PY -from hendrics.io import find_file_in_allowed_paths, get_file_type -from hendrics.io import save_as_ascii, save_as_qdp, read_header_key, ref_mjd -from hendrics.io import main, main_filter_events, remove_pds -from . import cleanup_test_dir -import pytest -import glob -from astropy.modeling import models -from astropy.modeling.core import Model +from . import cleanup_test_dir try: FileNotFoundError @@ -238,7 +249,7 @@ def test_filter_events(self, fmt): outfile = "bubu" + fmt save_events(events, outfile) main_filter_events([outfile, "--emin", "4", "--emax", "6"]) - outfile_filt = hen_root(outfile) + f"_4-6keV" + HEN_FILE_EXTENSION + outfile_filt = hen_root(outfile) + "_4-6keV" + HEN_FILE_EXTENSION events2 = load_events(outfile_filt) assert np.allclose(events.time[1:], events2.time) assert np.allclose(events.cal_pi[1:], events2.cal_pi) @@ -348,7 +359,9 @@ def test_load_and_save_cpds_all(self, fmt): pds.lc1 = Lightcurve(np.arange(2), [1, 2]) pds.lc2 = [Lightcurve(np.arange(2), [1, 2]), Lightcurve(np.arange(2), [3, 4])] - with pytest.warns(UserWarning, match="Saving multiple light curves is not supported"): + with pytest.warns( + UserWarning, match="Saving multiple light curves is not supported" + ): save_pds(pds, "bubup" + fmt, save_all=True) pds2 = load_pds("bubup" + fmt) for attr in [ @@ -467,7 +480,7 @@ def test_high_precision_split2(self): assert k == "double" def test_save_longcomplex(self): - val = np.longcomplex(1.01 + 2.3j) + val = np.clongdouble(1.01 + 2.3j) data = {"val": val} save_data(data, "bubu" + HEN_FILE_EXTENSION) data_out = load_data("bubu" + HEN_FILE_EXTENSION) @@ -602,7 +615,9 @@ def test_load_python_model_Astropy(self): def test_load_model_input_not_string(self): """Input is not a string""" - with pytest.raises(TypeError, match="modelstring has to be an existing file name"): + with pytest.raises( + TypeError, match="modelstring has to be an existing file name" + ): b, kind, _ = load_model(1) def test_load_model_input_file_doesnt_exist(self): diff --git a/hendrics/tests/test_lc.py b/hendrics/tests/test_lc.py index 83fb4e72..8822bc38 100644 --- a/hendrics/tests/test_lc.py +++ b/hendrics/tests/test_lc.py @@ -1,34 +1,20 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst -import shutil -import os import glob +import os import numpy as np -from astropy import log -from astropy.logger import AstropyUserWarning import pytest from stingray.lightcurve import Lightcurve + import hendrics as hen -from hendrics.tests import _dummy_par -from hendrics.fold import HAS_PINT -from hendrics import ( - fake, - fspec, - base, - calibrate, - create_gti, - exposure, - exvar, - io, - lcurve, - plot, - read_events, - rebin, -) -from hendrics.read_events import treat_event_file +from astropy import log +from astropy.logger import AstropyUserWarning from hendrics.io import HEN_FILE_EXTENSION, get_file_type from hendrics.lcurve import lcurve_from_events +from hendrics.read_events import treat_event_file +from hendrics.tests import _dummy_par + from . import cleanup_test_dir try: @@ -60,7 +46,9 @@ def test_treat_event_file_nustar(self): treat_event_file(self.fits_fileA, discard_calibration=True) lcurve_from_events(self.new_filename) - newfile = os.path.join(self.datadir, "monol_testA_nustar_fpma_lc" + HEN_FILE_EXTENSION) + newfile = os.path.join( + self.datadir, "monol_testA_nustar_fpma_lc" + HEN_FILE_EXTENSION + ) assert os.path.exists(newfile) type, data = get_file_type(newfile) assert type == "lc" @@ -93,7 +81,7 @@ def teardown_class(cls): cleanup_test_dir(".") -class TestFullRun(object): +class TestFullRun: """Test how command lines work. Usually considered bad practice, but in this @@ -102,15 +90,19 @@ class TestFullRun(object): Inspired by https://stackoverflow.com/questions/5387299/python-unittest-testcase-execution-order When command line is missing, uses some function calls - """ # NOQA + """ @classmethod def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) - cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) + cls.ev_fileA = os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ) + cls.ev_fileB = os.path.join( + cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION + ) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, @@ -126,8 +118,12 @@ def setup_class(cls): ) hen.read_events.main(command.split()) command = "{} {} -r {}".format( - os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), - os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION), + os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ), + os.path.join( + cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION + ), os.path.join(cls.datadir, "test.rmf"), ) hen.calibrate.main(command.split()) @@ -139,8 +135,9 @@ def test_lcurve(self): new_filename = os.path.join( os.path.join(self.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) ) - command = ("{0} -e {1} {2} --safe-interval " "{3} {4} --nproc 2 -b 0.5 -o {5}").format( - self.ev_fileAcal, 3, 50, 100, 300, new_filename + command = ( + f"{self.ev_fileAcal} -e {3} {50} --safe-interval " + f"{100} {300} --nproc 2 -b 0.5 -o {new_filename}" ) hen.lcurve.main(command.split()) @@ -200,12 +197,12 @@ def test_lcurve_noclobber(self): ) with pytest.warns(AstropyUserWarning, match="File exists, and noclobber"): - command = ("{0} -o {1} --noclobber").format(input_file, new_filename) + command = f"{input_file} -o {new_filename} --noclobber" hen.lcurve.main(command.split()) def test_lcurve_split(self): """Test lc with gti-split option.""" - command = "{0} {1} -g".format(self.ev_fileAcal, self.ev_fileBcal) + command = f"{self.ev_fileAcal} {self.ev_fileBcal} -g" hen.lcurve.main(command.split()) new_filename = os.path.join( self.datadir, @@ -220,15 +217,19 @@ def test_fits_lcurve0(self): """Test light curves from FITS.""" lcurve_ftools_orig = os.path.join(self.datadir, "lcurveA.fits") - lcurve_ftools = os.path.join(self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION) + lcurve_ftools = os.path.join( + self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION + ) command = "{0} --outfile {1}".format( self.ev_fileAcal, os.path.join(self.datadir, "lcurve_lc") ) hen.lcurve.main(command.split()) - assert os.path.exists(os.path.join(self.datadir, "lcurve_lc") + HEN_FILE_EXTENSION) + assert os.path.exists( + os.path.join(self.datadir, "lcurve_lc") + HEN_FILE_EXTENSION + ) - command = "--fits-input {0} --outfile {1}".format(lcurve_ftools_orig, lcurve_ftools) + command = f"--fits-input {lcurve_ftools_orig} --outfile {lcurve_ftools}" hen.lcurve.main(command.split()) with pytest.warns(AstropyUserWarning, match="File exists, and noclobber"): command = command + " --noclobber" @@ -236,7 +237,9 @@ def test_fits_lcurve0(self): def test_fits_lcurve1(self): """Test light curves from FITS.""" - lcurve_ftools = os.path.join(self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION) + lcurve_ftools = os.path.join( + self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION + ) lcurve_mp = os.path.join(self.datadir, "lcurve_lc" + HEN_FILE_EXTENSION) @@ -252,7 +255,9 @@ def test_fits_lcurve1(self): diff = lc_mp[:goodlen] - lc_ftools[:goodlen] - assert np.all(np.abs(diff) <= 1e-3), "Light curve data do not coincide between FITS and HEN" + assert np.all( + np.abs(diff) <= 1e-3 + ), "Light curve data do not coincide between FITS and HEN" def test_txt_lcurve(self): """Test light curves from txt.""" @@ -282,7 +287,9 @@ def test_txt_lcurve(self): def test_joinlcs(self): """Test produce joined light curves.""" - new_filename = os.path.join(self.datadir, "monol_test_joinlc" + HEN_FILE_EXTENSION) + new_filename = os.path.join( + self.datadir, "monol_test_joinlc" + HEN_FILE_EXTENSION + ) # because join_lightcurves separates by instrument new_actual_filename = os.path.join( self.datadir, "fpmamonol_test_joinlc" + HEN_FILE_EXTENSION @@ -305,7 +312,7 @@ def test_scrunchlcs(self): a_in = os.path.join(self.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) b_in = os.path.join(self.datadir, "monol_testB_E3-50_lc" + HEN_FILE_EXTENSION) out = os.path.join(self.datadir, "monol_test_scrunchlc" + HEN_FILE_EXTENSION) - command = "{0} {1} -o {2}".format(a_in, b_in, out) + command = f"{a_in} {b_in} -o {out}" a_lc = hen.io.load_lcurve(a_in) b_lc = hen.io.load_lcurve(b_in) @@ -322,7 +329,7 @@ def testbaselinelc(self): """Test produce scrunched light curves.""" a_in = os.path.join(self.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) out = os.path.join(self.datadir, "monol_test_baselc") - command = "{0} -o {1} -p 0.001 --lam 1e5".format(a_in, out) + command = f"{a_in} -o {out} -p 0.001 --lam 1e5" hen.lcurve.baseline_main(command.split()) out_lc = hen.io.load_lcurve(out + "_0" + HEN_FILE_EXTENSION) @@ -333,10 +340,12 @@ def testbaselinelc(self): def testbaselinelc_nooutroot(self): """Test produce scrunched light curves.""" a_in = os.path.join(self.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) - command = "{0} -p 0.001 --lam 1e5".format(a_in) + command = f"{a_in} -p 0.001 --lam 1e5" hen.lcurve.baseline_main(command.split()) - out_lc = hen.io.load_lcurve(hen.base.hen_root(a_in) + "_lc_baseline" + HEN_FILE_EXTENSION) + out_lc = hen.io.load_lcurve( + hen.base.hen_root(a_in) + "_lc_baseline" + HEN_FILE_EXTENSION + ) assert hasattr(out_lc, "base") gti_to_test = hen.io.load_events(self.ev_fileA).gti assert np.allclose(gti_to_test, out_lc.gti) @@ -401,15 +410,20 @@ def test_save_excvar_wrong_norm_from_lc(self): def test_create_gti_lc(self): """Test creating a GTI file.""" fname = os.path.join(self.datadir, "monol_testA_E3-50_lc") + HEN_FILE_EXTENSION - command = "{0} -f counts>0 -c --debug".format(fname) + command = f"{fname} -f counts>0 -c --debug" hen.create_gti.main(command.split()) def test_apply_gti_lc(self): """Test applying a GTI file.""" fname = os.path.join(self.datadir, "monol_testA_E3-50_gti") + HEN_FILE_EXTENSION - lcfname = os.path.join(self.datadir, "monol_testA_E3-50_lc") + HEN_FILE_EXTENSION - lcoutname = os.path.join(self.datadir, "monol_testA_E3-50_lc_gtifilt") + HEN_FILE_EXTENSION - command = "{0} -a {1} --debug".format(lcfname, fname) + lcfname = ( + os.path.join(self.datadir, "monol_testA_E3-50_lc") + HEN_FILE_EXTENSION + ) + lcoutname = ( + os.path.join(self.datadir, "monol_testA_E3-50_lc_gtifilt") + + HEN_FILE_EXTENSION + ) + command = f"{lcfname} -a {fname} --debug" hen.create_gti.main(command.split()) hen.io.load_lcurve(lcoutname) @@ -423,24 +437,28 @@ def test_plot_lcurve_baseline(self): def test_pds_fits(self): """Test PDS production with light curves obtained from FITS files.""" - lcurve_ftools = os.path.join(self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION) - command = "{0} --save-all -f 128".format(lcurve_ftools) + lcurve_ftools = os.path.join( + self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION + ) + command = f"{lcurve_ftools} --save-all -f 128" hen.fspec.main(command.split()) def test_pds_txt(self): """Test PDS production with light curves obtained from txt files.""" lcurve_txt = os.path.join(self.datadir, "lcurve_txt_lc" + HEN_FILE_EXTENSION) - command = "{0} --save-all -f 128".format(lcurve_txt) + command = f"{lcurve_txt} --save-all -f 128" hen.fspec.main(command.split()) def test_exposure(self): """Test exposure calculations from unfiltered files.""" lcname = os.path.join(self.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) ufname = os.path.join(self.datadir, "monol_testA_uf.evt") - command = "{0} {1}".format(lcname, ufname) + command = f"{lcname} {ufname}" hen.exposure.main(command.split()) - fname = os.path.join(self.datadir, "monol_testA_E3-50_lccorr" + HEN_FILE_EXTENSION) + fname = os.path.join( + self.datadir, "monol_testA_E3-50_lccorr" + HEN_FILE_EXTENSION + ) assert os.path.exists(fname) ftype, contents = hen.io.get_file_type(fname) diff --git a/hendrics/tests/test_ml_timing.py b/hendrics/tests/test_ml_timing.py index 7f7e1650..4cbe079f 100644 --- a/hendrics/tests/test_ml_timing.py +++ b/hendrics/tests/test_ml_timing.py @@ -1,10 +1,15 @@ -import pytest import numpy as np -from hendrics.ml_timing import normalized_template, normalized_template_func -from hendrics.ml_timing import ml_pulsefit, minimum_phase_diff +import pytest + +from hendrics.ml_timing import ( + minimum_phase_diff, + ml_pulsefit, + normalized_template, + normalized_template_func, +) -class TestTiming(object): +class TestTiming: @classmethod def setup_class(cls): cls.phases = np.arange(0.5 / 64, 1, 1 / 64) diff --git a/hendrics/tests/test_phaseogram.py b/hendrics/tests/test_phaseogram.py index b463d424..4f791d39 100644 --- a/hendrics/tests/test_phaseogram.py +++ b/hendrics/tests/test_phaseogram.py @@ -1,18 +1,24 @@ +import os +import subprocess as sp import warnings -from astropy.io.fits import Header -from stingray.lightcurve import Lightcurve -from stingray.events import EventList + import numpy as np -from hendrics.io import save_events, HEN_FILE_EXTENSION, load_folding -from hendrics.efsearch import main_zsearch -from hendrics.phaseogram import main_phaseogram, run_interactive_phaseogram -from hendrics.phaseogram import InteractivePhaseogram, BinaryPhaseogram +import pytest +from stingray.events import EventList +from stingray.lightcurve import Lightcurve + +from astropy.io.fits import Header from hendrics.base import hen_root -from hendrics.fold import HAS_PINT +from hendrics.efsearch import main_zsearch +from hendrics.io import HEN_FILE_EXTENSION, load_folding, save_events +from hendrics.phaseogram import ( + BinaryPhaseogram, + InteractivePhaseogram, + main_phaseogram, + run_interactive_phaseogram, +) from hendrics.plot import plot_folding -import os -import pytest -import subprocess as sp + from . import cleanup_test_dir @@ -79,7 +85,7 @@ def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") fits_file = os.path.join(cls.datadir, "monol_testA.evt") - command = "HENreadevents {0}".format(fits_file) + command = f"HENreadevents {fits_file}" sp.check_call(command.split()) cls.real_event_file = os.path.join( @@ -122,7 +128,9 @@ def test_phaseogram_input_periodogram(self, label): ] ) - @pytest.mark.parametrize("norm", ["to1", "mediansub", "mediannorm", "meansub", "meannorm"]) + @pytest.mark.parametrize( + "norm", ["to1", "mediansub", "mediannorm", "meansub", "meannorm"] + ) def test_phaseogram_input_norm(self, norm): evfile = self.dum main_phaseogram( @@ -197,7 +205,9 @@ def test_phaseogram_deorbit(self, withfX): withbt = not withfX create_parfile(par, withfX=withfX, withell1=withell1, withbt=withbt) - ip = run_interactive_phaseogram(evfile, 9.9, test=True, nbin=16, nt=8, deorbit_par=par) + ip = run_interactive_phaseogram( + evfile, 9.9, test=True, nbin=16, nt=8, deorbit_par=par + ) ip.update(1) with warnings.catch_warnings(record=True) as ws: ip.recalculate(1) @@ -270,7 +280,9 @@ def test_phaseogram_input_f_change_binary_deorbit(self, use_ell1): evfile = self.dum par = "orbit.par" create_parfile(par, withell1=use_ell1, withbt=not use_ell1) - ip = run_interactive_phaseogram(evfile, 9.9, test=True, binary=True, deorbit_par=par) + ip = run_interactive_phaseogram( + evfile, 9.9, test=True, binary=True, deorbit_par=par + ) ip.update(1) with warnings.catch_warnings(record=True) as ws: ip.recalculate(1) diff --git a/hendrics/tests/test_phasetag.py b/hendrics/tests/test_phasetag.py index 048ce96a..2df60b71 100644 --- a/hendrics/tests/test_phasetag.py +++ b/hendrics/tests/test_phasetag.py @@ -1,9 +1,11 @@ import os -from astropy.io import fits + import numpy as np import pytest -from ..phasetag import main_phasetag +from astropy.io import fits + +from ..phasetag import main_phasetag from . import cleanup_test_dir @@ -120,7 +122,9 @@ def test_phase_tag_invalid1(self): ) def test_phase_tag_parfile(self): - with pytest.raises(NotImplementedError, match="This part is not yet implemented"): + with pytest.raises( + NotImplementedError, match="This part is not yet implemented" + ): main_phasetag([self.fits_fileA, "--parfile", "bubu.par", "--test"]) @classmethod diff --git a/hendrics/tests/test_read_events.py b/hendrics/tests/test_read_events.py index b13113e2..1fd95c57 100644 --- a/hendrics/tests/test_read_events.py +++ b/hendrics/tests/test_read_events.py @@ -1,24 +1,25 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst import os -import glob -import pytest -import numpy as np +import numpy as np +import pytest from stingray.events import EventList -from hendrics.read_events import treat_event_file + +import hendrics as hen +from astropy.utils import minversion +from hendrics.fake import main from hendrics.io import ( HEN_FILE_EXTENSION, load_data, - save_events, load_events, + ref_mjd, + save_events, ) -from hendrics.io import ref_mjd from hendrics.io import main as main_readfile -from hendrics.fake import main -import hendrics as hen +from hendrics.read_events import treat_event_file + from . import cleanup_test_dir -from astropy.utils import minversion STINGRAY_LT_2_0 = not minversion(np, "2.0.0.dev") @@ -226,12 +227,15 @@ def setup_class(cls): cls.fits_file, ] ) - cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) - cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) + cls.ev_fileA = os.path.join( + cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ) + cls.ev_fileB = os.path.join( + cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION + ) def test_start(self): """Make any warnings in setup_class be dumped here.""" - pass def test_treat_event_file_nustar(self): treat_event_file(self.fits_fileA) @@ -254,7 +258,9 @@ def test_treat_event_file_xmm(self): assert "pi" in data and data["pi"].size > 0 def test_treat_event_file_xte_se(self): - treat_event_file(self.fits_file_xte, split_by_detector=False, bin_time_for_occultations=1) + treat_event_file( + self.fits_file_xte, split_by_detector=False, bin_time_for_occultations=1 + ) new_filename = "xte_test_xte_pca_ev" + HEN_FILE_EXTENSION assert os.path.exists(os.path.join(self.datadir, new_filename)) data = load_data(os.path.join(self.datadir, new_filename)) @@ -313,7 +319,9 @@ def test_treat_event_file_xmm_lensplit(self): def test_split_events(self): treat_event_file(self.fits_fileA) - filea = os.path.join(self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + filea = os.path.join( + self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ) files = hen.read_events.main_splitevents([filea, "-l", "50"]) for f in files: @@ -322,12 +330,16 @@ def test_split_events(self): def test_split_events_at_mjd(self): treat_event_file(self.fits_fileA) - filea = os.path.join(self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + filea = os.path.join( + self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ) data = load_events(filea) mean_met = np.mean(data.time) mean_mjd = mean_met / 86400 + data.mjdref - files = hen.read_events.main_splitevents([filea, "--split-at-mjd", f"{mean_mjd}"]) + files = hen.read_events.main_splitevents( + [filea, "--split-at-mjd", f"{mean_mjd}"] + ) assert "before" in files[0] assert "after" in files[1] @@ -339,14 +351,16 @@ def test_split_events_at_mjd(self): def test_split_events_bad_overlap_raises(self): treat_event_file(self.fits_fileA) - filea = os.path.join(self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + filea = os.path.join( + self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION + ) with pytest.raises(ValueError, match="Overlap cannot be >=1. Exiting."): hen.read_events.split_eventlist(filea, 10, overlap=1.5) def test_load_events(self): """Test event file reading.""" - command = "{}".format(self.fits_fileA) + command = f"{self.fits_fileA}" hen.read_events.main(command.split()) ev = hen.io.load_events(self.ev_fileA) assert hasattr(ev, "header") @@ -364,14 +378,14 @@ def test_load_events_with_2_cpus(self): def test_load_events_split(self): """Test event file splitting.""" - command = "{0} -g --min-length 0".format(self.fits_fileB) + command = f"{self.fits_fileB} -g --min-length 0" hen.read_events.main(command.split()) new_filename = os.path.join( self.datadir, "monol_testB_nustar_fpmb_gti000_ev" + HEN_FILE_EXTENSION, ) assert os.path.exists(new_filename) - command = "{0}".format(new_filename) + command = f"{new_filename}" hen.lcurve.main(command.split()) new_filename = os.path.join( self.datadir, @@ -385,12 +399,12 @@ def test_load_events_split(self): def test_load_events_noclobber(self): """Test event file reading w. noclobber option.""" with pytest.warns(UserWarning, match="exists and using noclobber. Skipping"): - command = "{0} --noclobber".format(self.fits_fileB) + command = f"{self.fits_fileB} --noclobber" hen.read_events.main(command.split()) def test_fix_gaps_events(self): """Test event file reading w. noclobber option.""" - command = "{0} --fill-small-gaps 4".format(self.fits_fileB) + command = f"{self.fits_fileB} --fill-small-gaps 4" hen.read_events.main(command.split()) @classmethod diff --git a/hendrics/timelags.py b/hendrics/timelags.py index 40369c76..a0cd482c 100644 --- a/hendrics/timelags.py +++ b/hendrics/timelags.py @@ -1,16 +1,17 @@ -# -*- coding: utf-8 -*- - from astropy import log -from .io import load_pds -from .io import save_as_qdp + from .base import hen_root +from .io import load_pds, save_as_qdp def main(args=None): import argparse + from .base import _add_default_args - description = "Read timelags from cross spectrum results and save them" " to a qdp file" + description = ( + "Read timelags from cross spectrum results and save them" " to a qdp file" + ) parser = argparse.ArgumentParser(description=description) parser.add_argument("files", help="List of files", nargs="+") diff --git a/hendrics/varenergy.py b/hendrics/varenergy.py index 5fbadb56..c607d962 100644 --- a/hendrics/varenergy.py +++ b/hendrics/varenergy.py @@ -1,23 +1,23 @@ -# -*- coding: utf-8 -*- """ @author: marta """ import warnings + +import numpy as np + from astropy import log from astropy.table import Table -from astropy.logger import AstropyUserWarning -import numpy as np try: - from stingray.varenergyspectrum import VarEnergySpectrum as VES from stingray.varenergyspectrum import ( + CountSpectrum, + CovarianceSpectrum, LagSpectrum, RmsSpectrum, - CovarianceSpectrum, - CountSpectrum, _decode_energy_specification, ) + from stingray.varenergyspectrum import VarEnergySpectrum as VES except ImportError: VES = object warnings.warn("Please update stingray to the latest version.") @@ -25,7 +25,6 @@ from .base import hen_root, interpret_bintime from .io import load_events -from .io import save_as_qdp def varenergy_to_astropy_table(spectrum): @@ -125,6 +124,7 @@ def _spectrum_function(self): # pragma: no cover def main(args=None): import argparse + from .base import _add_default_args, check_negative_numbers_in_args description = "Calculates variability-energy spectra" @@ -158,7 +158,9 @@ def main(args=None): default=None, help="Reference band when relevant", ) - parser.add_argument("--rms", default=False, action="store_true", help="Calculate rms") + parser.add_argument( + "--rms", default=False, action="store_true", help="Calculate rms" + ) parser.add_argument( "--covariance", default=False, @@ -264,7 +266,8 @@ def main(args=None): if fname2 is not None: events2 = load_events(fname2) if not args.use_pi and ( - events.energy is None or (events2 is not None and events2.energy is None) + events.energy is None + or (events2 is not None and events2.energy is None) ): raise ValueError( "If --use-pi is not specified, event lists must " From 031f6ff0c7c8e53f87ba312bdefc72cb4535eaaa Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 12:32:45 +0200 Subject: [PATCH 19/58] Ruff it up --- notebooks/deadtime_model_zhang.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/notebooks/deadtime_model_zhang.py b/notebooks/deadtime_model_zhang.py index f36b0dc9..6f6eebdf 100644 --- a/notebooks/deadtime_model_zhang.py +++ b/notebooks/deadtime_model_zhang.py @@ -62,7 +62,9 @@ def h(k, n, td, tb, tau): @jit(nopython=True) def A(k, r0, td, tb, tau): if k == 0: - return r0 * tb * (1 + 2 * sum([h(1, n, td, tb, tau) for n in range(1, INFINITE)])) + return ( + r0 * tb * (1 + 2 * sum([h(1, n, td, tb, tau) for n in range(1, INFINITE)])) + ) eq39_sums = [ h(k + 1, n, td, tb, tau) - 2 * h(k, n, td, tb, tau) + h(k - 1, n, td, tb, tau) @@ -130,7 +132,11 @@ def pds_model_zhang_back(N, rate, td, tb, limit_k=60): for k in range(1, N) ] - P[j] = 2 / Nph * (N * safe_A(0, r0, td, tb, tau, limit_k=limit_k) + 2 * sum(eq8_sums)) + P[j] = ( + 2 + / Nph + * (N * safe_A(0, r0, td, tb, tau, limit_k=limit_k) + 2 * sum(eq8_sums)) + ) maxf = 0.5 / tb df = maxf / len(P) From e6e24c93334e847afad3f60e5ceff18ce93ab2c1 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 12:33:04 +0200 Subject: [PATCH 20/58] Eliminate black --- pyproject.toml | 24 +++++++++--------------- tox.ini | 8 -------- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 431935bd..dbff6f0d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -259,9 +259,7 @@ filterwarnings = [ [tool.ruff] lint.select = ["ALL"] exclude=[ - "astropy/extern/*", - "*_parsetab.py", - "*_lextab.py", + "notebooks/*.ipynb", "*.svg" ] lint.ignore = [ # NOTE: non-permanent exclusions should be added to `.ruff.toml` instead. @@ -338,11 +336,6 @@ lint.ignore = [ # NOTE: non-permanent exclusions should be added to `.ruff.toml [tool.ruff.lint.extend-per-file-ignores] "setup.py" = ["INP001"] # Part of configuration, not a package. ".github/workflows/*.py" = ["INP001"] -"astropy/modeling/models/__init__.py" = ["F405"] -"astropy/utils/decorators.py" = [ - "D214", "D215", # keep Examples section indented. - "D411", # sphinx treats spaced example sections as real sections -] "test_*.py" = [ "ANN201", # Public function without return type annotation "B018", # UselessExpression @@ -354,11 +347,6 @@ lint.ignore = [ # NOTE: non-permanent exclusions should be added to `.ruff.toml "docs/*.py" = [ "INP001", # implicit-namespace-package. The examples are not a package. ] -"examples/*.py" = [ - "E402", # Imports are done as needed. - "INP001", # implicit-namespace-package. The examples are not a package. - "T203" # pprint found -] [tool.ruff.lint.flake8-annotations] ignore-fully-untyped = true @@ -424,5 +412,11 @@ ignore-words-list = """ wirth, """ -[tool.black] -line-length = 100 +[tool.docformatter] + # The ``summaries`` are not (yet) 75 characters because the summary lines can't be + # automatically wrapped and must be re-written, which should be done at some point. + recursive = true + wrap-summaries = 1000 + wrap-descriptions = 75 + black = true + syntax = "numpy" diff --git a/tox.ini b/tox.ini index c912c9d6..59a8ed31 100644 --- a/tox.ini +++ b/tox.ini @@ -97,11 +97,3 @@ deps = commands = pre-commit install-hooks pre-commit run {posargs:--color always --all-files --show-diff-on-failure} - -[testenv:black] -skip_install = true -changedir = . -description = use black -deps = - black ~= 23.1.0 -commands = black --check hendrics From fff0d20b729c1863c87fb0a690e9d63ec7c08b80 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 12:40:02 +0200 Subject: [PATCH 21/58] Avoid relative import from top packages --- hendrics/tests/test_ffa.py | 5 ++--- hendrics/tests/test_phasetag.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/hendrics/tests/test_ffa.py b/hendrics/tests/test_ffa.py index a83d01f1..1705c683 100644 --- a/hendrics/tests/test_ffa.py +++ b/hendrics/tests/test_ffa.py @@ -1,10 +1,9 @@ import numpy as np +from stingray.efsearch import fit from stingray.events import EventList +from stingray.ffa import ffa_search from stingray.lightcurve import Lightcurve -from ..efsearch import fit -from ..ffa import ffa_search - # @pytest.mark.skipif('not HAS_NUMBA') def test_ffa(): diff --git a/hendrics/tests/test_phasetag.py b/hendrics/tests/test_phasetag.py index 2df60b71..5e6effd0 100644 --- a/hendrics/tests/test_phasetag.py +++ b/hendrics/tests/test_phasetag.py @@ -2,10 +2,10 @@ import numpy as np import pytest +from stingray.phasetag import main_phasetag from astropy.io import fits -from ..phasetag import main_phasetag from . import cleanup_test_dir From 5b1d8ca7f50b7b38439e38de7feeea19b74b0542 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 13:09:57 +0200 Subject: [PATCH 22/58] Fix line style --- hendrics/base.py | 29 +++------- hendrics/binary.py | 19 ++----- hendrics/create_gti.py | 25 +++------ hendrics/efsearch.py | 114 ++++++++++---------------------------- hendrics/exposure.py | 24 ++------ hendrics/fake.py | 31 +++-------- hendrics/ffa.py | 12 +--- hendrics/fold.py | 62 ++++++--------------- hendrics/fspec.py | 16 ++---- hendrics/io.py | 37 +++---------- hendrics/lcurve.py | 30 +++------- hendrics/ml_timing.py | 4 +- hendrics/modeling.py | 4 +- hendrics/phaseogram.py | 75 +++++++------------------ hendrics/phasetag.py | 24 ++------ hendrics/plot.py | 44 ++++----------- hendrics/power_colors.py | 4 +- hendrics/read_events.py | 42 ++++---------- hendrics/save_as_xspec.py | 4 +- hendrics/sum_fspec.py | 4 +- hendrics/timelags.py | 4 +- 21 files changed, 155 insertions(+), 453 deletions(-) diff --git a/hendrics/base.py b/hendrics/base.py index 4ddb8a0d..f6617bda 100644 --- a/hendrics/base.py +++ b/hendrics/base.py @@ -459,9 +459,7 @@ def deorbit_events(events, parameter_file=None, invert=False, ephem=None): """ events = copy.deepcopy(events) if parameter_file is None: - warnings.warn( - "No parameter file specified for deorbit. Returning" " unaltered event list" - ) + warnings.warn("No parameter file specified for deorbit. Returning" " unaltered event list") return events if not os.path.exists(parameter_file): raise FileNotFoundError(f"Parameter file {parameter_file} does not exist") @@ -537,6 +535,7 @@ def check_negative_numbers_in_args(args): args = sys.argv[1:] newargs = [] for arg in args: + arg = str(arg) try: # Has to be a number, has to be negative assert -float(arg) > 0 @@ -659,9 +658,7 @@ def hist1d_numba_seq(a, bins, ranges, use_memmap=False, tmp=None): if bins > 10**7 and use_memmap: if tmp is None: tmp = tempfile.NamedTemporaryFile("w+").name - hist_arr = np.lib.format.open_memmap( - tmp, mode="w+", dtype=a.dtype, shape=(bins,) - ) + hist_arr = np.lib.format.open_memmap(tmp, mode="w+", dtype=a.dtype, shape=(bins,)) else: hist_arr = np.zeros((bins,), dtype=a.dtype) @@ -694,9 +691,7 @@ def hist2d_numba_seq(x, y, bins, ranges): >>> assert np.all(H == Hn) """ H = np.zeros((bins[0], bins[1]), dtype=np.uint64) - return _hist2d_numba_seq( - H, np.array([x, y]), np.asarray(list(bins)), np.asarray(ranges) - ) + return _hist2d_numba_seq(H, np.array([x, y]), np.asarray(list(bins)), np.asarray(ranges)) @njit(nogil=True, parallel=False) @@ -727,9 +722,7 @@ def hist3d_numba_seq(tracks, bins, ranges): >>> assert np.all(H == Hn) """ H = np.zeros((bins[0], bins[1], bins[2]), dtype=np.uint64) - return _hist3d_numba_seq( - H, np.asarray(tracks), np.asarray(list(bins)), np.asarray(ranges) - ) + return _hist3d_numba_seq(H, np.asarray(tracks), np.asarray(list(bins)), np.asarray(ranges)) @njit(nogil=True, parallel=False) @@ -770,9 +763,7 @@ def hist1d_numba_seq_weight(a, weights, bins, ranges, use_memmap=False, tmp=None if bins > 10**7 and use_memmap: if tmp is None: tmp = tempfile.NamedTemporaryFile("w+").name - hist_arr = np.lib.format.open_memmap( - tmp, mode="w+", dtype=a.dtype, shape=(bins,) - ) + hist_arr = np.lib.format.open_memmap(tmp, mode="w+", dtype=a.dtype, shape=(bins,)) else: hist_arr = np.zeros((bins,), dtype=a.dtype) @@ -877,10 +868,7 @@ def _histnd_numba_seq(H, tracks, bins, ranges, slice_int): for t in range(tracks.shape[1]): slicearr = np.array( - [ - (tracks[dim, t] - ranges[dim, 0]) * delta[dim] - for dim in range(tracks.shape[0]) - ] + [(tracks[dim, t] - ranges[dim, 0]) * delta[dim] for dim in range(tracks.shape[0])] ) good = np.all((slicearr < bins) & (slicearr >= 0)) @@ -1153,8 +1141,7 @@ def find_peaks_in_image(image, n=5, rough=False, **kwargs): """ if not HAS_SKIMAGE or rough: best_cands = [ - np.unravel_index(idx, image.shape) - for idx in np.argpartition(image.flatten(), -n)[-n:] + np.unravel_index(idx, image.shape) for idx in np.argpartition(image.flatten(), -n)[-n:] ] __best_stats = [image[bci] for bci in best_cands] best_cands = np.asarray(best_cands)[np.argsort(__best_stats)][::-1] diff --git a/hendrics/binary.py b/hendrics/binary.py index faf5dce7..f6cc077b 100644 --- a/hendrics/binary.py +++ b/hendrics/binary.py @@ -37,12 +37,7 @@ def get_header_info(obj): dec = header["DEC_PNT"] a = SkyCoord(ra, dec, unit="degree") - info.raj = ( - (a.ra.to_string("hourangle")) - .replace("s", "") - .replace("h", ":") - .replace("m", ":") - ) + info.raj = (a.ra.to_string("hourangle")).replace("s", "").replace("h", ":").replace("m", ":") info.decj = (a.dec.to_string()).replace("s", "").replace("d", ":").replace("m", ":") if hasattr(obj, "e_interval"): e0, e1 = obj.e_interval @@ -94,9 +89,7 @@ def save_lc_to_binary(lc, filename): return lcinfo -def save_events_to_binary( - events, filename, bin_time, tstart=None, emin=None, emax=None -): +def save_events_to_binary(events, filename, bin_time, tstart=None, emin=None, emax=None): """Save an event list to binary format. Parameters @@ -129,9 +122,7 @@ def save_events_to_binary( if emin is not None and emax is not None: if not hasattr(events, "energy") or events.energy is None: - raise ValueError( - "Energy filtering requested for uncalibrated event " "list" - ) + raise ValueError("Energy filtering requested for uncalibrated event " "list") good = (events.energy >= emin) & (events.energy < emax) events = events.apply_mask(good) @@ -183,9 +174,7 @@ def save_inf(lcinfo, info, filename): with open(filename, "w") as f: print( - " Data file name without suffix " " = {}".format( - filename.replace(".inf", "") - ), + " Data file name without suffix " " = {}".format(filename.replace(".inf", "")), file=f, ) print( diff --git a/hendrics/create_gti.py b/hendrics/create_gti.py index 6d311987..11db3025 100644 --- a/hendrics/create_gti.py +++ b/hendrics/create_gti.py @@ -31,9 +31,7 @@ def filter_gti_by_length(gti, minimum_length): return np.array(newgti) -def create_gti( - fname, filter_expr, safe_interval=[0, 0], outfile=None, minimum_length=0 -): +def create_gti(fname, filter_expr, safe_interval=[0, 0], outfile=None, minimum_length=0): """Create a GTI list by using boolean operations on file data. Parameters @@ -75,9 +73,7 @@ def create_gti( if hasattr(data, "internal_array_attrs"): array_attrs = data.internal_array_attrs() mod_array_attrs = [attr.replace("_", "") for attr in array_attrs] - locals().update( - zip(mod_array_attrs, [getattr(data, attr) for attr in array_attrs]) - ) + locals().update(zip(mod_array_attrs, [getattr(data, attr) for attr in array_attrs])) good = eval(filter_expr) @@ -85,9 +81,7 @@ def create_gti( gti = filter_gti_by_length(gti, minimum_length) - outfile = _assign_value_if_none( - outfile, hen_root(fname) + "_gti" + HEN_FILE_EXTENSION - ) + outfile = _assign_value_if_none(outfile, hen_root(fname) + "_gti" + HEN_FILE_EXTENSION) save_data({"gti": gti, "mjdref": mjdref, "__sr__class__type__": "gti"}, outfile) return gti @@ -114,9 +108,7 @@ def apply_gti(fname, gti, outname=None, minimum_length=0): data._mask = None newext = "_gtifilt" + HEN_FILE_EXTENSION - outname = _assign_value_if_none( - outname, fname.replace(HEN_FILE_EXTENSION, "") + newext - ) + outname = _assign_value_if_none(outname, fname.replace(HEN_FILE_EXTENSION, "") + newext) save_data(data, outname) return newgti @@ -129,8 +121,7 @@ def main(args=None): from .base import _add_default_args, check_negative_numbers_in_args description = ( - "Create GTI files from a filter expression, or applies " - "previously created GTIs to a file" + "Create GTI files from a filter expression, or applies " "previously created GTIs to a file" ) parser = argparse.ArgumentParser(description=description) @@ -151,8 +142,7 @@ def main(args=None): "--create-only", default=False, action="store_true", - help="If specified, creates GTIs without applying" - + "them to files (Default: False)", + help="If specified, creates GTIs without applying" + "them to files (Default: False)", ) parser.add_argument( @@ -200,8 +190,7 @@ def main(args=None): filter_expr = args.filter if filter_expr is None and args.apply_gti is None: sys.exit( - "Please specify filter expression (-f option) or input " - "GTI file (-a option)" + "Please specify filter expression (-f option) or input " "GTI file (-a option)" ) for fname in files: diff --git a/hendrics/efsearch.py b/hendrics/efsearch.py index 9656afa3..8ad2d595 100644 --- a/hendrics/efsearch.py +++ b/hendrics/efsearch.py @@ -248,9 +248,7 @@ def decide_binary_parameters( Omegas = np.random.uniform(omega_range[0], omega_range[1], nOmega) for Omega in Omegas: - block_of_data.append( - [freq, fdot, X, TWOPI / Omega, False, 0.0, 0.0, 0.0] - ) + block_of_data.append([freq, fdot, X, TWOPI / Omega, False, 0.0, 0.0, 0.0]) df = pd.DataFrame(block_of_data, columns=columns) _save_df_to_csv(df, csv_file, reset=reset) @@ -293,12 +291,8 @@ def folding_orbital_search( for T0 in T0s: # one iteration new_values = times - X * np.sin(2 * np.pi * (times - T0) / Porb) - new_values = new_values - X * np.sin( - 2 * np.pi * (new_values - T0) / Porb - ) - fgrid, stats = fun( - new_values, np.array([freq]), fdots=fdot, **fun_kwargs - ) + new_values = new_values - X * np.sin(2 * np.pi * (new_values - T0) / Porb) + fgrid, stats = fun(new_values, np.array([freq]), fdots=fdot, **fun_kwargs) if stats[0] > max_stats: max_stats = stats[0] best_T0 = T0 @@ -351,9 +345,7 @@ def mod(num, n2): @njit() -def shift_and_sum( - repeated_profiles, lshift, qshift, splat_prof, base_shift, quadbaseshift -): +def shift_and_sum(repeated_profiles, lshift, qshift, splat_prof, base_shift, quadbaseshift): nprof = repeated_profiles.shape[0] nbin = splat_prof.size twonbin = nbin * 2 @@ -363,9 +355,7 @@ def shift_and_sum( total_shift = mod(np.rint(total_shift), nbin) total_shift_int = int(total_shift) - splat_prof[:] += repeated_profiles[ - k, nbin - total_shift_int : twonbin - total_shift_int - ] + splat_prof[:] += repeated_profiles[k, nbin - total_shift_int : twonbin - total_shift_int] return splat_prof @@ -564,9 +554,7 @@ def transient_search( times -= meantime maxerr = check_phase_error_after_casting_to_double(np.max(times), f1, fdot) - log.info( - f"Maximum error on the phase expected when casting to double: " f"{maxerr}" - ) + log.info(f"Maximum error on the phase expected when casting to double: " f"{maxerr}") if maxerr > 1 / nbin / 10: warnings.warn( "Casting to double produces non-negligible phase errors. " @@ -690,9 +678,7 @@ def plot_transient_search(results, gif_name=None): f"{gif_name}: Possible candidate at step {i}: {best_f} Hz (~{maxline:.1f} sigma)" ) elif maxline >= 5 and i_f == 0: # pragma: no cover - print( - f"{gif_name}: Candidate at step {i}: {best_f} Hz (~{maxline:.1f} sigma)" - ) + print(f"{gif_name}: Candidate at step {i}: {best_f} Hz (~{maxline:.1f} sigma)") axf.plot(f, mean_line, lw=1, c="k", zorder=10, label="mean", ls="-") @@ -720,9 +706,7 @@ def plot_transient_search(results, gif_name=None): if HAS_IMAGEIO: imageio.v3.imwrite(gif_name, all_images, duration=1000.0) else: - warnings.warn( - "imageio needed to save the transient search results " "into a gif image." - ) + warnings.warn("imageio needed to save the transient search results " "into a gif image.") return all_images @@ -822,9 +806,7 @@ def search_with_qffa_step( # dn = max(1, int(nbin / oversample)) linbinshifts = np.linspace(-nbin * npfact, nbin * npfact, int(oversample * npfact)) if search_fdot: - quabinshifts = np.linspace( - -nbin * npfact, nbin * npfact, int(oversample * npfact) - ) + quabinshifts = np.linspace(-nbin * npfact, nbin * npfact, int(oversample * npfact)) else: quabinshifts = np.array([0]) @@ -906,9 +888,7 @@ def search_with_qffa( maxerr = check_phase_error_after_casting_to_double(np.max(times), f1, fdot) if maxerr > 1 / nbin / 10: - warnings.warn( - f"Maximum error on the phase expected when casting to " f"double: {maxerr}" - ) + warnings.warn(f"Maximum error on the phase expected when casting to " f"double: {maxerr}") warnings.warn( "Casting to double produces non-negligible phase errors. " "Please use shorter light curves.", @@ -1071,9 +1051,7 @@ def folding_search( fdotepsilon = 1e-2 * fdotstep trial_fdots = np.arange(fdotmin, fdotmax + fdotepsilon, fdotstep) if len(trial_fdots) > 1: - log.info( - f"Searching {len(trial_freqs)} frequencies and {len(trial_fdots)} fdots" - ) + log.info(f"Searching {len(trial_freqs)} frequencies and {len(trial_fdots)} fdots") else: log.info(f"Searching {len(trial_freqs)} frequencies") @@ -1150,14 +1128,11 @@ def print_qffa_results(best_cand_table): if len(newtable[good]) == 0: print("No pulsations found. Best candidate and upper limit:") good = 0 - newtable["Pulsed amplitude (%)"] = [ - f"<{a:g} (90%)" for a in newtable["pulse_amp_ul_0.9"] - ] + newtable["Pulsed amplitude (%)"] = [f"<{a:g} (90%)" for a in newtable["pulse_amp_ul_0.9"]] else: print("Best candidate(s):") newtable["Pulsed amplitude (%)"] = [ - f"{a:g} ± {e:g}" - for (a, e) in zip(newtable["pulse_amp"], newtable["pulse_amp_err"]) + f"{a:g} ± {e:g}" for (a, e) in zip(newtable["pulse_amp"], newtable["pulse_amp_err"]) ] print(newtable["mjd", "f", "fdot", "fddot", "power", "Pulsed amplitude (%)"][good]) @@ -1252,10 +1227,7 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): input_ef_periodogram.M = 1 ntrial = input_ef_periodogram.stat.size - if ( - hasattr(input_ef_periodogram, "oversample") - and input_ef_periodogram.oversample is not None - ): + if hasattr(input_ef_periodogram, "oversample") and input_ef_periodogram.oversample is not None: ntrial /= input_ef_periodogram.oversample ntrial = int(ntrial) if input_ef_periodogram.kind == "Z2n": @@ -1283,10 +1255,7 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): best_cands = find_peaks_in_image(input_ef_periodogram.stat, n=n_cands) fddot = 0 - if ( - hasattr(input_ef_periodogram, "fddots") - and input_ef_periodogram.fddots is not None - ): + if hasattr(input_ef_periodogram, "fddots") and input_ef_periodogram.fddots is not None: fddot = input_ef_periodogram.fddots best_cand_table = Table( @@ -1345,10 +1314,7 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): for i, idx in enumerate(best_cands): f_idx = fdot_idx = fddot_idx = 0 - if ( - len(input_ef_periodogram.stat.shape) > 1 - and input_ef_periodogram.stat.shape[0] > 1 - ): + if len(input_ef_periodogram.stat.shape) > 1 and input_ef_periodogram.stat.shape[0] > 1: f_idx, fdot_idx = idx allfreqs = input_ef_periodogram.freq[f_idx, :] allfdots = input_ef_periodogram.freq[:, fdot_idx] @@ -1359,9 +1325,7 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): input_ef_periodogram.fdots[f_idx, fdot_idx], ) max_stat = input_ef_periodogram.stat[f_idx, fdot_idx] - sig_e1_m, sig_e1 = power_confidence_limits( - max_stat, c=0.68, n=input_ef_periodogram.N - ) + sig_e1_m, sig_e1 = power_confidence_limits(max_stat, c=0.68, n=input_ef_periodogram.N) fmin, fmax, fdotmin, fdotmax = get_xy_boundaries_from_level( input_ef_periodogram.freq, input_ef_periodogram.fdots, @@ -1376,9 +1340,7 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): allstats_f = input_ef_periodogram.stat f = input_ef_periodogram.freq[f_idx] max_stat = input_ef_periodogram.stat[f_idx] - sig_e1_m, sig_e1 = power_confidence_limits( - max_stat, c=0.68, n=input_ef_periodogram.N - ) + sig_e1_m, sig_e1 = power_confidence_limits(max_stat, c=0.68, n=input_ef_periodogram.N) fmin, fmax = get_boundaries_from_level( input_ef_periodogram.freq, input_ef_periodogram.stat, sig_e1_m, f ) @@ -1391,9 +1353,7 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): if input_ef_periodogram.ncounts is None: continue - sig_0, sig_1 = power_confidence_limits( - max_stat, c=0.90, n=input_ef_periodogram.N - ) + sig_0, sig_1 = power_confidence_limits(max_stat, c=0.90, n=input_ef_periodogram.N) amp = amp_err = amp_ul = amp_1 = amp_0 = np.nan if max_stat < detlev: amp_ul = a_from_ssig(sig_1, input_ef_periodogram.ncounts) * 100 @@ -1442,8 +1402,7 @@ def _analyze_qffa_results(input_ef_periodogram, fname=None): if fname is not None: Table({"fdot": allfdots, "stat": allstats_fdot}).write( - f'{fname.replace(HEN_FILE_EXTENSION, "")}' - f"_cand_{n_cands - i - 1}_f{f}.dat", + f'{fname.replace(HEN_FILE_EXTENSION, "")}' f"_cand_{n_cands - i - 1}_f{f}.dat", overwrite=True, format="ascii", ) @@ -1581,8 +1540,7 @@ def _common_parser(args=None): "--step", default=None, type=float, - help="Step size of the frequency axis. Defaults to " - "1/oversample/obs_length. ", + help="Step size of the frequency axis. Defaults to " "1/oversample/obs_length. ", ) parser.add_argument( "--oversample", @@ -1612,8 +1570,7 @@ def _common_parser(args=None): ) parser.add_argument( "--transient", - help="Look for transient emission (produces an animated" - " GIF with the dynamic Z search)", + help="Look for transient emission (produces an animated" " GIF with the dynamic Z search)", default=False, action="store_true", ) @@ -1782,8 +1739,7 @@ def _common_main(args, func): if nbin / n < 8: nbin = n * 8 warnings.warn( - f"The number of bins is too small for Z search." - f"Increasing to {nbin}" + f"The number of bins is too small for Z search." f"Increasing to {nbin}" ) results = search_with_qffa( events.time, @@ -1805,9 +1761,7 @@ def _common_main(args, func): "The Fast Folding Algorithm functionality is experimental. Use" " with care, and feel free to report any issues." ) - results = search_with_ffa( - events.time, args.fmin, args.fmax, nbin=args.nbin, n=n - ) + results = search_with_ffa(events.time, args.fmin, args.fmax, nbin=args.nbin, n=n) ref_time = events.time[0] length = events.time.max() - events.time.min() @@ -1849,9 +1803,7 @@ def _common_main(args, func): pepoch=mjdref + ref_time / 86400, oversample=args.oversample, ) - efperiodogram.upperlim = pf_upper_limit( - np.max(stats), events.time.size, n=args.N - ) + efperiodogram.upperlim = pf_upper_limit(np.max(stats), events.time.size, n=args.N) efperiodogram.ncounts = events.time.size best_peaks = None if args.find_candidates: @@ -1958,9 +1910,7 @@ def main_z2vspf(args=None): type=int, help="Number of trial values for the pulsed fraction", ) - parser.add_argument( - "--outfile", default=None, type=str, help="Output table file name" - ) + parser.add_argument("--outfile", default=None, type=str, help="Output table file name") parser.add_argument( "--show-z-values", nargs="+", @@ -2000,9 +1950,7 @@ def main_z2vspf(args=None): if args.emin is not None or args.emax is not None: events, elabel = filter_energy(events, args.emin, args.emax) - result_table = z2_vs_pf( - events, deadtime=0.0, ntrials=args.ntrial, outfile=outfile, N=args.N - ) + result_table = z2_vs_pf(events, deadtime=0.0, ntrials=args.ntrial, outfile=outfile, N=args.N) if HAS_MPL: fig = plt.figure("Results", figsize=(10, 6)) plt.scatter(result_table["pf"] * 100, result_table["z2"]) @@ -2056,9 +2004,7 @@ def main_accelsearch(args=None): type=float, help="Maximum frequency to search, in Hz", ) - parser.add_argument( - "--nproc", default=1, type=int, help="Number of processors to use" - ) + parser.add_argument("--nproc", default=1, type=int, help="Number of processors to use") parser.add_argument( "--zmax", default=100, @@ -2163,9 +2109,7 @@ def main_accelsearch(args=None): t0 = GTI[0, 0] Nbins = int(np.rint(max_length / dt)) if Nbins > 10**8: - log.info( - f"The number of bins is more than 100 millions: {Nbins}. " "Using memmap." - ) + log.info(f"The number of bins is more than 100 millions: {Nbins}. " "Using memmap.") dt = adjust_dt_for_power_of_two(dt, max_length) diff --git a/hendrics/exposure.py b/hendrics/exposure.py index 3200b186..a7836a00 100644 --- a/hendrics/exposure.py +++ b/hendrics/exposure.py @@ -46,9 +46,7 @@ def get_livetime_per_bin(times, events, priors, dt=None, gti=None): [[time[0] - dt[0]/2, time[-1] + dt[-1]/2]] """ - assert len(events) == len( - priors - ), "`events` and `priors` must be of the same length" + assert len(events) == len(priors), "`events` and `priors` must be of the same length" dt = _assign_value_if_none(dt, np.median(np.diff(times))) @@ -177,15 +175,9 @@ def _plot_dead_time_from_uf(uf_file, outroot="expo"): bins = np.percentile(dead_times, np.linspace(0, 100, 1000)) hist_all, bins_all = histogram(dead_times, bins=bins, density=True) - hist_shield, bins_shield = histogram( - dead_times[shields > 0], bins=bins, density=True - ) - hist_noshield, bins_noshield = histogram( - dead_times[shields == 0], bins=bins, density=True - ) - hist_shld_hi, bins_shld_hi = histogram( - dead_times[shld_hi > 0], bins=bins, density=True - ) + hist_shield, bins_shield = histogram(dead_times[shields > 0], bins=bins, density=True) + hist_noshield, bins_noshield = histogram(dead_times[shields == 0], bins=bins, density=True) + hist_shld_hi, bins_shld_hi = histogram(dead_times[shld_hi > 0], bins=bins, density=True) bin_centers = bins[:-1] + np.diff(bins) / 2 fig = plt.figure("Dead time distribution", figsize=(10, 10)) @@ -302,9 +294,7 @@ def correct_lightcurve(lc_file, uf_file, outname=None, expo_limit=1e-7): outname : str Output file name """ - outname = _assign_value_if_none( - outname, hen_root(lc_file) + "_lccorr" + HEN_FILE_EXTENSION - ) + outname = _assign_value_if_none(outname, hen_root(lc_file) + "_lccorr" + HEN_FILE_EXTENSION) ftype, contents = get_file_type(lc_file) @@ -355,9 +345,7 @@ def main(args=None): default=None, help="Root of output file names", ) - parser.add_argument( - "--plot", help="Plot on window", default=False, action="store_true" - ) + parser.add_argument("--plot", help="Plot on window", default=False, action="store_true") _add_default_args(parser, ["loglevel", "debug"]) args = check_negative_numbers_in_args(args) diff --git a/hendrics/fake.py b/hendrics/fake.py index 03e27558..b36d6459 100644 --- a/hendrics/fake.py +++ b/hendrics/fake.py @@ -66,9 +66,7 @@ def _fill_in_default_information(tbheader): False, "TRUE if timestamps corrected by gnd sware", ) - tbheader["COMMENT"] = ( - "MJDREFI+MJDREFF = epoch of Jan 1, 2010, in TT " "time system." - ) + tbheader["COMMENT"] = "MJDREFI+MJDREFF = epoch of Jan 1, 2010, in TT " "time system." tbheader["TIMEUNIT"] = ("s", "unit for time keywords") return tbheader @@ -133,9 +131,7 @@ def generate_fake_fits_observation( inheader = _clean_up_header(inheader) ev_list = event_list.time - gti = assign_value_if_none( - event_list.gti, np.asarray([[ev_list[0], ev_list[-1]]]) - ) + gti = assign_value_if_none(event_list.gti, np.asarray([[ev_list[0], ev_list[-1]]])) mission = assign_value_if_none(mission, event_list.mission) instr = assign_value_if_none(instr, event_list.instr) tstart = assign_value_if_none(tstart, gti[0, 0]) @@ -307,9 +303,7 @@ def _read_light_curve(filename): return lc -def acceptance_rejection( - dt, counts_per_bin, t0=0.0, poissonize_n_events=False, deadtime=0.0 -): +def acceptance_rejection(dt, counts_per_bin, t0=0.0, poissonize_n_events=False, deadtime=0.0): """ Examples -------- @@ -526,8 +520,7 @@ def main_scramble(args=None): from .base import _add_default_args, check_negative_numbers_in_args description = ( - "Scramble the events inside an event list, maintaining the same " - "energies and GTIs" + "Scramble the events inside an event list, maintaining the same " "energies and GTIs" ) parser = argparse.ArgumentParser(description=description) @@ -588,9 +581,7 @@ def main_scramble(args=None): emin, emax = args.energy_interval event_list, elabel = filter_energy(event_list, emin, emax) if elabel != "Energy": - raise ValueError( - "You are filtering by energy but the data are not calibrated" - ) + raise ValueError("You are filtering by energy but the data are not calibrated") new_event_list = scramble( event_list, @@ -616,9 +607,7 @@ def main_scramble(args=None): if args.energy_interval is not None: label += f"_{emin:g}-{emax:g}keV" - outfile = args.fname.replace( - HEN_FILE_EXTENSION, f"{label}" + HEN_FILE_EXTENSION - ) + outfile = args.fname.replace(HEN_FILE_EXTENSION, f"{label}" + HEN_FILE_EXTENSION) save_events(new_event_list, outfile) return outfile @@ -664,9 +653,7 @@ def main(args=None): default="events.evt", help="Output file name", ) - parser.add_argument( - "-i", "--instrument", type=str, default=None, help="Instrument name" - ) + parser.add_argument("-i", "--instrument", type=str, default=None, help="Instrument name") parser.add_argument("-m", "--mission", type=str, default=None, help="Mission name") parser.add_argument( "--tstart", @@ -719,9 +706,7 @@ def main(args=None): tstop = assign_value_if_none(args.tstop, 1024) dt = (tstop - tstart) / 1024 t = np.arange(tstart, tstop + 1, dt) - lc = Lightcurve( - time=t, counts=args.ctrate * dt + np.zeros_like(t), dt=dt - ) + lc = Lightcurve(time=t, counts=args.ctrate * dt + np.zeros_like(t), dt=dt) event_list.simulate_times(lc) nevents = len(event_list.time) event_list.pi = np.zeros(nevents, dtype=int) diff --git a/hendrics/ffa.py b/hendrics/ffa.py index 44cc8dcd..642f0af7 100644 --- a/hendrics/ffa.py +++ b/hendrics/ffa.py @@ -299,9 +299,7 @@ def ffa_step(array, step, ntables): array_reshaped_dum[prof_n, :] = sum_arrays(array[start, :], rolled[:]) else: - array_reshaped_dum[prof_n, :] = sum_arrays( - array[start, :], array[jumpstart, :] - ) + array_reshaped_dum[prof_n, :] = sum_arrays(array[start, :], array[jumpstart, :]) return array_reshaped_dum @@ -325,9 +323,7 @@ def _ffa(array_reshaped, bin_period, ntables, z_n_n=2): stats = np.zeros(ntables) for i in range(array_reshaped.shape[0]): - stats[i] = _z_n_fast_cached( - array_reshaped[i, :], cached_cos, cached_sin, n=z_n_n - ) + stats[i] = _z_n_fast_cached(array_reshaped[i, :], cached_cos, cached_sin, n=z_n_n) return periods, stats @@ -357,9 +353,7 @@ def _quick_rebin(counts, current_rebin): >>> assert np.allclose(reb, [3, 7, 11, 15, 19]) """ n = int(counts.size // current_rebin) - rebinned_counts = np.sum( - counts[: n * current_rebin].reshape(n, current_rebin), axis=1 - ) + rebinned_counts = np.sum(counts[: n * current_rebin].reshape(n, current_rebin), axis=1) return rebinned_counts diff --git a/hendrics/fold.py b/hendrics/fold.py index 929b7d0b..e01f0f91 100644 --- a/hendrics/fold.py +++ b/hendrics/fold.py @@ -32,9 +32,7 @@ def show_progress(a): # import pint HAS_PINT = True except (ImportError, urllib.error.URLError): - warnings.warn( - "PINT is not installed. " "Some pulsar functionality will not be available" - ) + warnings.warn("PINT is not installed. " "Some pulsar functionality will not be available") HAS_PINT = False from .base import deorbit_events @@ -108,9 +106,7 @@ def create_template_from_profile_sins( return template, additional_phase -def create_template_from_profile( - phase, profile, profile_err, imagefile="template.png", norm=1 -): +def create_template_from_profile(phase, profile, profile_err, imagefile="template.png", norm=1): """ Parameters ---------- @@ -419,9 +415,7 @@ def get_TOAs_from_events(events, folding_length, *frequency_derivatives, **kwarg from .ml_timing import ml_pulsefit - pars, errs = ml_pulsefit( - profile, template, calculate_errors=True, fit_base=fit_base - ) + pars, errs = ml_pulsefit(profile, template, calculate_errors=True, fit_base=fit_base) if np.any(np.isnan(pars)) or pars[0] == 0.0 or np.any(np.isnan(errs)): warnings.warn( @@ -449,9 +443,7 @@ def get_TOAs_from_events(events, folding_length, *frequency_derivatives, **kwarg factor = np.std(phs) / np.mean(phs_errs) if phs.size > 15: - log.info( - "Correcting TOA errors for the real scatter. Don't trust them literally" - ) + log.info("Correcting TOA errors for the real scatter. Don't trust them literally") # print(phs, phs_errs, factor) toa_errs = toa_errs * factor @@ -491,9 +483,7 @@ def dbl_cos_fit_func(p, x): base = p[0] startidx = 1 first_harm = p[startidx] * np.cos(2 * np.pi * x + 2 * np.pi * p[startidx + 1]) - second_harm = p[startidx + 2] * np.cos( - 4.0 * np.pi * x + 4 * np.pi * p[startidx + 3] - ) + second_harm = p[startidx + 2] * np.cos(4.0 * np.pi * x + 4 * np.pi * p[startidx + 3]) return base + first_harm + second_harm @@ -529,9 +519,7 @@ def adjust_amp_phase(pars): return pars -def fit_profile_with_sinusoids( - profile, profile_err, debug=False, nperiods=1, baseline=False -): +def fit_profile_with_sinusoids(profile, profile_err, debug=False, nperiods=1, baseline=False): """ Fit a folded profile with the std_fold_fit_func. @@ -590,20 +578,16 @@ def fit_profile_with_sinusoids( if debug: log.debug(guess_pars) plt.plot(x, std_fold_fit_func(guess_pars, x), "r--") - fit_pars, success = optimize.leastsq( - std_residuals, guess_pars[:], args=(x, profile) - ) + fit_pars, success = optimize.leastsq(std_residuals, guess_pars[:], args=(x, profile)) if debug: plt.plot(x, std_fold_fit_func(fit_pars, x), "g--") - fit_pars[startidx : startidx + 2] = adjust_amp_phase( - fit_pars[startidx : startidx + 2] - ) + fit_pars[startidx : startidx + 2] = adjust_amp_phase(fit_pars[startidx : startidx + 2]) fit_pars[startidx + 2 : startidx + 4] = adjust_amp_phase( fit_pars[startidx + 2 : startidx + 4] ) - chisq = np.sum( - (profile - std_fold_fit_func(fit_pars, x)) ** 2 / profile_err**2 - ) / (len(profile) - (startidx + 4)) + chisq = np.sum((profile - std_fold_fit_func(fit_pars, x)) ** 2 / profile_err**2) / ( + len(profile) - (startidx + 4) + ) if debug: plt.plot(x, std_fold_fit_func(fit_pars, x), "b--") if chisq < chisq_save: @@ -692,9 +676,7 @@ def run_folding( smooth_window = np.min([len(profile), 10]) smooth_window = _check_odd(smooth_window) - smoothed_profile = savgol_filter( - profile, window_length=smooth_window, polyorder=3, mode="wrap" - ) + smoothed_profile = savgol_filter(profile, window_length=smooth_window, polyorder=3, mode="wrap") profile = np.concatenate((profile, profile)) smooth = np.concatenate((smoothed_profile, smoothed_profile)) @@ -702,9 +684,7 @@ def run_folding( if plot_energy: histen, _ = np.histogram(energy, bins=biny) - hist2d, _, _ = np.histogram2d( - phases.astype(np.float64), energy, bins=(binx, biny) - ) + hist2d, _, _ = np.histogram2d(phases.astype(np.float64), energy, bins=(binx, biny)) binx = np.concatenate((binx[:-1], binx + 1)) meanbins = (binx[:-1] + binx[1:]) / 2 @@ -745,9 +725,7 @@ def run_folding( color="k", zorder=3, ) - err_low, err_high = poisson_conf_interval( - smooth, interval="frequentist-confidence", sigma=3 - ) + err_low, err_high = poisson_conf_interval(smooth, interval="frequentist-confidence", sigma=3) try: ax0.fill_between( @@ -795,9 +773,7 @@ def run_folding( errs = [] meannrgs = (biny[:-1] + biny[1:]) / 2 for i, prof in enumerate(hist2d_save.T): - smooth = savgol_filter( - prof, window_length=smooth_window, polyorder=3, mode="wrap" - ) + smooth = savgol_filter(prof, window_length=smooth_window, polyorder=3, mode="wrap") mean = np.mean(smooth) shift = 3 * np.sqrt(mean) max = np.max(smooth) @@ -860,12 +836,8 @@ def main_fold(args=None): help="Initial frequency to fold", default=None, ) - parser.add_argument( - "--fdot", type=float, required=False, help="Initial fdot", default=0 - ) - parser.add_argument( - "--fddot", type=float, required=False, help="Initial fddot", default=0 - ) + parser.add_argument("--fdot", type=float, required=False, help="Initial fdot", default=0) + parser.add_argument("--fddot", type=float, required=False, help="Initial fddot", default=0) parser.add_argument( "--tref", type=float, diff --git a/hendrics/fspec.py b/hendrics/fspec.py index 18bd9df9..abc87fb2 100644 --- a/hendrics/fspec.py +++ b/hendrics/fspec.py @@ -176,9 +176,7 @@ def _provide_periodograms(events, fftlen, dt, norm): for new_ev in _distribute_events(events, fftlen): # Hack: epsilon slightly below zero, to allow for a GTI to be recognized as such new_ev.gti[:, 1] += dt / 10 - pds = AveragedPowerspectrum( - new_ev, dt=dt, segment_size=fftlen, norm=norm, silent=True - ) + pds = AveragedPowerspectrum(new_ev, dt=dt, segment_size=fftlen, norm=norm, silent=True) pds.fftlen = fftlen yield pds @@ -413,9 +411,7 @@ def calc_cpds( "series (e.g. both events or both light curves)" ) - if (emin is not None or emax is not None) and ( - ftype1 != "events" or ftype2 != "events" - ): + if (emin is not None or emax is not None) and (ftype1 != "events" or ftype2 != "events"): warnings.warn("Energy selection only makes sense for event lists") if ftype1 == "events": lc1, _ = filter_energy(lc1, emin, emax) @@ -696,9 +692,7 @@ def dumpdyn_main(args=None): help=("List of files in any valid HENDRICS " "format for PDS or CPDS"), nargs="+", ) - parser.add_argument( - "--noplot", help="plot results", default=False, action="store_true" - ) + parser.add_argument("--noplot", help="plot results", default=False, action="store_true") args = parser.parse_args(args) @@ -758,9 +752,7 @@ def main(args=None): "--norm", type=str, default="leahy", - help="Normalization to use" - + " (Accepted: leahy and rms;" - + ' Default: "leahy")', + help="Normalization to use" + " (Accepted: leahy and rms;" + ' Default: "leahy")', ) parser.add_argument( "--noclobber", diff --git a/hendrics/io.py b/hendrics/io.py index 1a155c8b..6568032d 100644 --- a/hendrics/io.py +++ b/hendrics/io.py @@ -126,9 +126,7 @@ def find_peaks(self, conflevel=99.0): n_summed_spectra=int(self.M), ) else: - threshold = fold_detection_level( - nbin=int(self.nbin), epsilon=epsilon, ntrial=ntrial - ) + threshold = fold_detection_level(nbin=int(self.nbin), epsilon=epsilon, ntrial=ntrial) if len(self.stat.shape) == 1: best_peaks, best_stat = search_best_peaks(self.freq, self.stat, threshold) @@ -205,10 +203,7 @@ def filter_energy(ev: EventList, emin: float, emax: float) -> Tuple[EventList, s # For some reason the doctest doesn't work if I don't do this instead # of using warnings.warn if elabel == "": - log.error( - "No Energy or PI information available. " - "No energy filter applied to events" - ) + log.error("No Energy or PI information available. " "No energy filter applied to events") return ev, "" if emax is None and emin is None: @@ -502,9 +497,7 @@ def get_file_type(fname, raw_data=False): if "Lightcurve" in ftype_raw: ftype = "lc" fun = load_lcurve - elif ("Powercolor" in ftype_raw) or ( - "StingrayTimeseries" in ftype_raw and "hue" in contents - ): + elif ("Powercolor" in ftype_raw) or ("StingrayTimeseries" in ftype_raw and "hue" in contents): ftype = "powercolor" fun = load_timeseries elif "StingrayTimeseries" in ftype_raw or "Color" in ftype_raw: @@ -709,9 +702,7 @@ def load_folding(fname): # ---- Functions to save PDSs -def save_pds( - cpds, fname, save_all=False, save_dyn=False, no_auxil=False, save_lcs=False -): +def save_pds(cpds, fname, save_all=False, save_dyn=False, no_auxil=False, save_lcs=False): """Save PDS in a file.""" from .base import mkdir_p @@ -758,9 +749,7 @@ def save_pds( lc = getattr(cpds, lcattr) if isinstance(lc, Iterable): if len(lc) > 1: - warnings.warn( - "Saving multiple light curves is not supported. Saving only one" - ) + warnings.warn("Saving multiple light curves is not supported. Saving only one") lc = lc[0] if isinstance(lc, Lightcurve): save_lcurve(lc, lc_name) @@ -821,9 +810,7 @@ def save_pds( def remove_pds(fname): """Remove the pds file and the directory with auxiliary information.""" outdir, _ = splitext_improved(fname) - modelfiles = glob.glob( - os.path.join(outdir, fname.replace(HEN_FILE_EXTENSION, "__mod*__.p")) - ) + modelfiles = glob.glob(os.path.join(outdir, fname.replace(HEN_FILE_EXTENSION, "__mod*__.p"))) for mfile in modelfiles: os.unlink(mfile) if os.path.exists(outdir): @@ -1039,9 +1026,7 @@ def _save_data_nc(struct, fname, kind="data"): # If a (long)double, split it in integer + floating part. # If the number is below zero, also use a logarithm of 10 before # that, so that we don't lose precision - var_I, var_F, var_log10, kind_str = _split_high_precision_number( - k, var, probesize - ) + var_I, var_F, var_log10, kind_str = _split_high_precision_number(k, var, probesize) values.extend([var_I, var_log10, var_F, kind_str]) formats.extend(["i8", "i8", "f8", str]) varnames.extend([k + "_I", k + "_L", k + "_F", k + "_k"]) @@ -1330,9 +1315,7 @@ def save_model(model, fname="model.p", constraints=None): nargs = model.__code__.co_argcount nkwargs = len(model.__defaults__) if not nargs - nkwargs == 1: - raise TypeError( - "Accepted callable models have only one " "non-keyword argument" - ) + raise TypeError("Accepted callable models have only one " "non-keyword argument") modeldata["kind"] = "callable" modeldata["constraints"] = constraints else: @@ -1388,9 +1371,7 @@ def load_model(modelstring): nargs = model.__code__.co_argcount nkwargs = len(model.__defaults__) if not nargs - nkwargs == 1: - raise TypeError( - "Accepted callable models have only one " "non-keyword argument" - ) + raise TypeError("Accepted callable models have only one " "non-keyword argument") return model, "callable", constraints diff --git a/hendrics/lcurve.py b/hendrics/lcurve.py index 9512471e..92560f84 100644 --- a/hendrics/lcurve.py +++ b/hendrics/lcurve.py @@ -188,9 +188,7 @@ def scrunch_lightcurve_objs(lclist): return lc0 -def scrunch_lightcurves( - lcfilelist, outfile="out_scrlc" + HEN_FILE_EXTENSION, save_joint=False -): +def scrunch_lightcurves(lcfilelist, outfile="out_scrlc" + HEN_FILE_EXTENSION, save_joint=False): """Create a single light curve from input light curves. Light curves are appended when they cover different times, and summed when @@ -234,9 +232,7 @@ def scrunch_lightcurves( return lc0 -def filter_lc_gtis( - lc, safe_interval=None, delete=False, min_length=0, return_borders=False -): +def filter_lc_gtis(lc, safe_interval=None, delete=False, min_length=0, return_borders=False): """Filter a light curve for GTIs. Parameters @@ -388,8 +384,7 @@ def lcurve_from_events( elif e_interval is not None and np.all(np.array(e_interval) > 0): if not hasattr(evdata, "energy") or evdata.energy is None: raise ValueError( - "No energy information is present in the file." - + " Did you run HENcalibrate?" + "No energy information is present in the file." + " Did you run HENcalibrate?" ) es = evdata.energy good = np.logical_and(es > e_interval[0], es <= e_interval[1]) @@ -405,9 +400,7 @@ def lcurve_from_events( ) # Assign default value if None - outfile = assign_value_if_none( - outfile, hen_root(f) + tag + deorbit_tag + weight_on_tag + "_lc" - ) + outfile = assign_value_if_none(outfile, hen_root(f) + tag + deorbit_tag + weight_on_tag + "_lc") # Take out extension from name, if present, then give extension. This # avoids multiple extensions @@ -465,9 +458,7 @@ def lcurve_from_events( lc.instr = instr lc.e_interval = e_interval - lc = filter_lc_gtis( - lc, safe_interval=safe_interval, delete=False, min_length=min_length - ) + lc = filter_lc_gtis(lc, safe_interval=safe_interval, delete=False, min_length=min_length) if len(lc.gti) == 0: warnings.warn(f"No GTIs above min_length ({min_length}s) found.") @@ -642,8 +633,7 @@ def lcurve_from_fits( dt *= 86400 except Exception: warnings.warn( - "Assuming that TIMEDEL is the median difference between the" - " light curve times", + "Assuming that TIMEDEL is the median difference between the" " light curve times", AstropyUserWarning, ) dt = np.median(np.diff(time)) @@ -942,9 +932,7 @@ def main(args=None): default=False, action="store_true", ) - parser.add_argument( - "-d", "--outdir", type=str, default=None, help="Output directory" - ) + parser.add_argument("-d", "--outdir", type=str, default=None, help="Output directory") parser.add_argument( "--noclobber", help="Do not overwrite existing files", @@ -969,9 +957,7 @@ def main(args=None): type=str, help="Use a given attribute of the event list as weights for the light curve", ) - parser = _add_default_args( - parser, ["deorbit", "output", "loglevel", "debug", "nproc"] - ) + parser = _add_default_args(parser, ["deorbit", "output", "loglevel", "debug", "nproc"]) args = check_negative_numbers_in_args(args) args = parser.parse_args(args) diff --git a/hendrics/ml_timing.py b/hendrics/ml_timing.py index 68cf129b..d2cdad42 100644 --- a/hendrics/ml_timing.py +++ b/hendrics/ml_timing.py @@ -194,9 +194,7 @@ def normalized_template(template, tomax=False, subtract_min=True): """ dph = 1 / template.size phase = np.arange(dph / 2, 1, dph) - return normalized_template_func(template, tomax=tomax, subtract_min=subtract_min)( - phase - ) + return normalized_template_func(template, tomax=tomax, subtract_min=subtract_min)(phase) # def estimate_errors(best_fit_templ, ntrial=100, profile_err=None): diff --git a/hendrics/modeling.py b/hendrics/modeling.py index 351c6a1a..9e6a2159 100644 --- a/hendrics/modeling.py +++ b/hendrics/modeling.py @@ -15,9 +15,7 @@ def main_model(args=None): from .base import _add_default_args, check_negative_numbers_in_args - description = ( - "Fit frequency spectra (PDS, CPDS, cospectrum) " "with user-defined models" - ) + description = "Fit frequency spectra (PDS, CPDS, cospectrum) " "with user-defined models" parser = argparse.ArgumentParser(description=description) parser.add_argument("files", help="List of light curve files", nargs="+") diff --git a/hendrics/phaseogram.py b/hendrics/phaseogram.py index f66e54c3..148af37f 100644 --- a/hendrics/phaseogram.py +++ b/hendrics/phaseogram.py @@ -197,12 +197,8 @@ def __init__( self.phases, self.times = phases, times vmin = None - self.pcolor = ax.pcolormesh( - phases, times, self.phaseogr.T, cmap=self.colormap, vmin=vmin - ) - self.colorbar = plt.colorbar( - self.pcolor, cax=colorbax, orientation="horizontal" - ) + self.pcolor = ax.pcolormesh(phases, times, self.phaseogr.T, cmap=self.colormap, vmin=vmin) + self.colorbar = plt.colorbar(self.pcolor, cax=colorbax, orientation="horizontal") ax.set_xlabel("Phase") def s2d(x): @@ -223,9 +219,7 @@ def d2s(x): self.lines = [] self.line_phases = np.arange(-2, 3, 0.5) for ph0 in self.line_phases: - (newline,) = ax.plot( - np.zeros_like(times) + ph0, times, zorder=10, lw=2, color="w" - ) + (newline,) = ax.plot(np.zeros_like(times) + ph0, times, zorder=10, lw=2, color="w") self.lines.append(newline) ax.set_xlim([0, 2]) @@ -244,29 +238,19 @@ def newax_fn(*args, **kwargs): self._construct_widgets(**kwargs) self.closeax = self.fig.add_axes([0.15, 0.020, 0.15, 0.04]) - self.button_close = Button( - self.closeax, "Quit", color=axcolor, hovercolor="0.8" - ) + self.button_close = Button(self.closeax, "Quit", color=axcolor, hovercolor="0.8") self.recalcax = self.fig.add_axes([0.3, 0.020, 0.15, 0.04]) - self.button_recalc = Button( - self.recalcax, "Recalculate", color=axcolor, hovercolor="0.975" - ) + self.button_recalc = Button(self.recalcax, "Recalculate", color=axcolor, hovercolor="0.975") self.resetax = self.fig.add_axes([0.45, 0.020, 0.15, 0.04]) - self.button_reset = Button( - self.resetax, "Reset", color=axcolor, hovercolor="0.975" - ) + self.button_reset = Button(self.resetax, "Reset", color=axcolor, hovercolor="0.975") self.zoominax = self.fig.add_axes([0.6, 0.020, 0.1, 0.04]) - self.button_zoomin = Button( - self.zoominax, "+Zoom", color=axcolor, hovercolor="0.975" - ) + self.button_zoomin = Button(self.zoominax, "+Zoom", color=axcolor, hovercolor="0.975") self.zoomoutax = self.fig.add_axes([0.7, 0.020, 0.1, 0.04]) - self.button_zoomout = Button( - self.zoomoutax, "-Zoom", color=axcolor, hovercolor="0.975" - ) + self.button_zoomout = Button(self.zoomoutax, "-Zoom", color=axcolor, hovercolor="0.975") self.toaax = self.fig.add_axes([0.8, 0.020, 0.1, 0.04]) self.button_toa = Button(self.toaax, "TOA", color=axcolor, hovercolor="0.975") @@ -282,21 +266,13 @@ def newax_fn(*args, **kwargs): prof = np.sum(np.nan_to_num(self.unnorm_phaseogr), axis=1) nbin = len(prof) phas = np.linspace(0, 2, nbin + 1)[:-1] - (self.profile_fixed,) = self.profax.plot( - phas, prof, drawstyle="steps-post", color="grey" - ) - (self.profile,) = self.profax.plot( - phas, prof, drawstyle="steps-post", color="k" - ) + (self.profile_fixed,) = self.profax.plot(phas, prof, drawstyle="steps-post", color="grey") + (self.profile,) = self.profax.plot(phas, prof, drawstyle="steps-post", color="k") mean = np.mean(prof) - low, high = poisson_conf_interval( - mean, interval="frequentist-confidence", sigma=2 - ) + low, high = poisson_conf_interval(mean, interval="frequentist-confidence", sigma=2) self.profax.fill_between(phas, low, high, alpha=0.5) z2_label = get_H_label(phas, prof) - self.proftext = self.profax.text( - 0.1, 0.8, z2_label, transform=self.profax.transAxes - ) + self.proftext = self.profax.text(0.1, 0.8, z2_label, transform=self.profax.transAxes) if not test and not plot_only: plt.show() if plot_only: @@ -316,8 +292,7 @@ def recalculate(self, event): # pragma: no cover def toa(self, event): # pragma: no cover warnings.warn( - "This function was not implemented for this Phaseogram. " - "Try the basic one.", + "This function was not implemented for this Phaseogram. " "Try the basic one.", AstropyUserWarning, ) @@ -479,12 +454,8 @@ def get_timing_model_string(self): tm_string += f"PEPOCH {self.pepoch / 86400 + self.mjdref}\n" tm_string += f"PSRJ {self.object}\n" if self.position is not None: - tm_string += "RAJ {}\n".format( - self.position.ra.to_string("hour", sep=":") - ) - tm_string += "DECJ {}\n".format( - self.position.dec.to_string(sep=":") - ) + tm_string += "RAJ {}\n".format(self.position.ra.to_string("hour", sep=":")) + tm_string += "DECJ {}\n".format(self.position.dec.to_string(sep=":")) tm_string += f"F0 {self.freq}\n" tm_string += f"F1 {self.fdot}\n" @@ -795,9 +766,7 @@ def _line_delay_fun(self, times): orbital_period, asini, t0 = self._read_sliders() new_values = asini * np.sin(2 * np.pi * (times - t0) / orbital_period) - old_values = self.asini * np.sin( - 2 * np.pi * (times - self.t0) / (self.orbital_period) - ) + old_values = self.asini * np.sin(2 * np.pi * (times - self.t0) / (self.orbital_period)) return (new_values - old_values) * self.freq def _delay_fun(self, times): @@ -990,12 +959,8 @@ def main_phaseogram(args=None): help="Initial frequency to fold", default=None, ) - parser.add_argument( - "--fdot", type=float, required=False, help="Initial fdot", default=0 - ) - parser.add_argument( - "--fddot", type=float, required=False, help="Initial fddot", default=0 - ) + parser.add_argument("--fdot", type=float, required=False, help="Initial fdot", default=0) + parser.add_argument("--fddot", type=float, required=False, help="Initial fddot", default=0) parser.add_argument( "--periodogram", type=str, @@ -1076,9 +1041,7 @@ def main_phaseogram(args=None): with log.log_to_file("HENphaseogram.log"): if args.periodogram is None and args.freq is None: - raise ValueError( - "One of -f or --periodogram arguments MUST be " "specified" - ) + raise ValueError("One of -f or --periodogram arguments MUST be " "specified") elif args.periodogram is not None: periodogram = load_folding(args.periodogram) frequency = float(periodogram.peaks[0]) diff --git a/hendrics/phasetag.py b/hendrics/phasetag.py index abd2c083..e2e22daf 100644 --- a/hendrics/phasetag.py +++ b/hendrics/phasetag.py @@ -101,9 +101,7 @@ def phase_tag( f = frequency_derivatives[0] phase = pulse_phase(times, *frequency_derivatives, to_1=False) - gti_phases = pulse_phase( - (gti_mjd - pepoch) * 86400, *frequency_derivatives, to_1=False - ) + gti_phases = pulse_phase((gti_mjd - pepoch) * 86400, *frequency_derivatives, to_1=False) # ------- now apply period derivatives ------ @@ -118,15 +116,11 @@ def phase_tag( phase_to1 = phase - np.floor(phase) raw_profile, bins = np.histogram(phase_to1, bins=np.linspace(0, 1, nbin + 1)) - exposure = phase_exposure( - gti_phases[0, 0], gti_phases[-1, 1], 1, nbin=nbin, gti=gti_phases - ) + exposure = phase_exposure(gti_phases[0, 0], gti_phases[-1, 1], 1, nbin=nbin, gti=gti_phases) profile = raw_profile / exposure profile_err = np.sqrt(raw_profile) / exposure - sinpars, bu, bu = fit_profile( - profile, profile_err, nperiods=2, baseline=True, debug=test - ) + sinpars, bu, bu = fit_profile(profile, profile_err, nperiods=2, baseline=True, debug=test) fine_phases = np.linspace(0, 2, 1000 * 2) fitted_profile = std_fold_fit_func(sinpars, fine_phases) maxp = np.argmax(fitted_profile) @@ -143,9 +137,7 @@ def phase_tag( raw_profile, bins = np.histogram(phase_to1, bins=np.linspace(0, 1, nbin + 1)) - exposure = phase_exposure( - gti_phases[0, 0], gti_phases[-1, 1], 1, nbin=nbin, gti=gti_phases - ) + exposure = phase_exposure(gti_phases[0, 0], gti_phases[-1, 1], 1, nbin=nbin, gti=gti_phases) if np.any(np.logical_or(exposure != exposure, exposure == 0)): warnings.warn( "Exposure has NaNs or zeros. Profile is not normalized", @@ -288,9 +280,7 @@ def phase_tag_fits( if create: # then, create new column with orbital demodulation - newcol = pf.Column( - name="Orbit_bary", format="1D", unit="s", array=results.ev_list - ) + newcol = pf.Column(name="Orbit_bary", format="1D", unit="s", array=results.ev_list) # append it to new table newlist.append(newcol) @@ -317,9 +307,7 @@ def phase_tag_fits( newrec = pf.FITS_rec.from_columns(coldefs) # and new hdu - newtbhdu = pf.BinTableHDU( - data=newrec, header=tbhdu.header.copy(), name=hduname, uint=False - ) + newtbhdu = pf.BinTableHDU(data=newrec, header=tbhdu.header.copy(), name=hduname, uint=False) # Copy primary HDU from old file prihdu = hdulist[0].copy() diff --git a/hendrics/plot.py b/hendrics/plot.py index 847a7cfd..c16c27c0 100644 --- a/hendrics/plot.py +++ b/hendrics/plot.py @@ -210,15 +210,9 @@ def plot_powercolors(fnames): ts = load_data(fnames) - plot_power_colors( - ts["pc1"], ts["pc1_err"], ts["pc2"], ts["pc2_err"], plot_spans=True - ) - plot_hues( - ts["rms"], ts["rms_err"], ts["pc1"], ts["pc2"], polar=True, plot_spans=True - ) - plot_hues( - ts["rms"], ts["rms_err"], ts["pc1"], ts["pc2"], polar=False, plot_spans=True - ) + plot_power_colors(ts["pc1"], ts["pc1_err"], ts["pc2"], ts["pc2_err"], plot_spans=True) + plot_hues(ts["rms"], ts["rms_err"], ts["pc1"], ts["pc2"], polar=True, plot_spans=True) + plot_hues(ts["rms"], ts["rms_err"], ts["pc1"], ts["pc2"], polar=False, plot_spans=True) return ts @@ -499,9 +493,7 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No mean = np.mean(profile) - low, high = poisson_conf_interval( - mean, interval="frequentist-confidence", sigma=1 - ) + low, high = poisson_conf_interval(mean, interval="frequentist-confidence", sigma=1) ax.axhline(mean) ax.fill_between( @@ -511,9 +503,7 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No label=r"1-$\sigma c.l.$", alpha=0.5, ) - low, high = poisson_conf_interval( - mean, interval="frequentist-confidence", sigma=3 - ) + low, high = poisson_conf_interval(mean, interval="frequentist-confidence", sigma=3) ax.fill_between( [0, 2], [low, low], @@ -629,9 +619,7 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No cbar = plt.colorbar(pcol, cax=axcolor, ticks=colorticks) if len(cs.allsegs[0]) > 1: - warnings.warn( - "More than one contour found. " "Frequency estimates might be wrong" - ) + warnings.warn("More than one contour found. " "Frequency estimates might be wrong") else: for ax in (axffdot, axf): ax.axvline(cs.allsegs[0][0][:, 0].min(), label="90% conf. lim.") @@ -689,11 +677,7 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No axf.set_ylabel(ef.kind + " stat") axf.legend(loc=4) - if ( - hasattr(ef, "best_fits") - and ef.best_fits is not None - and not len(ef.stat.shape) > 1 - ): + if hasattr(ef, "best_fits") and ef.best_fits is not None and not len(ef.stat.shape) > 1: for f in ef.best_fits: xs = np.linspace(np.min(ef.freq), np.max(ef.freq), len(ef.freq) * 2) plt.plot(xs, f(xs)) @@ -706,11 +690,7 @@ def plot_folding(fnames, figname=None, xlog=None, ylog=None, output_data_file=No out = [ef.freq.flatten(), fdots.flatten(), ef.stat.flatten()] out_err = [None, None, None] - if ( - hasattr(ef, "best_fits") - and ef.best_fits is not None - and not len(ef.stat.shape) > 1 - ): + if hasattr(ef, "best_fits") and ef.best_fits is not None and not len(ef.stat.shape) > 1: for f in ef.best_fits: out.append(f(ef.freq.flatten())) out_err.append(None) @@ -898,12 +878,8 @@ def main(args=None): default=None, action="store_true", ) - parser.add_argument( - "--xlin", help="Use linear X axis", default=False, action="store_true" - ) - parser.add_argument( - "--ylin", help="Use linear Y axis", default=False, action="store_true" - ) + parser.add_argument("--xlin", help="Use linear X axis", default=False, action="store_true") + parser.add_argument("--ylin", help="Use linear Y axis", default=False, action="store_true") parser.add_argument( "--white-sub", help="Subtract Poisson noise (only applies to PDS)", diff --git a/hendrics/power_colors.py b/hendrics/power_colors.py index 20138cea..8a6a3e7a 100644 --- a/hendrics/power_colors.py +++ b/hendrics/power_colors.py @@ -90,9 +90,7 @@ def treat_power_colors( ) good = (scolor.pc1 > 0) & (scolor.pc2 > 0) if np.any(~good): - warnings.warn( - "Some (non-log) power colors are negative. Neglecting them", UserWarning - ) + warnings.warn("Some (non-log) power colors are negative. Neglecting them", UserWarning) scolor = scolor.apply_mask(good) if outfile is None: diff --git a/hendrics/read_events.py b/hendrics/read_events.py index 0cc09404..2cf8880a 100644 --- a/hendrics/read_events.py +++ b/hendrics/read_events.py @@ -91,9 +91,7 @@ def treat_event_file( good = lc.counts > 0 new_bad = (~good) & good_gti if np.any(new_bad): - warnings.warn( - f"Found zero counts in the light curve at times{lc.time[new_bad]}" - ) + warnings.warn(f"Found zero counts in the light curve at times{lc.time[new_bad]}") gti = create_gti_from_condition( lc.time, (good_gti & good), safe_interval=bin_time_for_occultations ) @@ -105,9 +103,7 @@ def treat_event_file( detector_id = events.detector_id if randomize_by is not None: - events.time += np.random.uniform( - -randomize_by / 2, randomize_by / 2, events.time.size - ) + events.time += np.random.uniform(-randomize_by / 2, randomize_by / 2, events.time.size) if fill_small_gaps is not None: events = events.fill_bad_time_intervals(fill_small_gaps) @@ -150,15 +146,12 @@ def treat_event_file( label = "gti" for ig, g in enumerate(gti_chunks): - outfile_local = ( - f"{outroot_local}_{label}{ig:03d}_ev" + HEN_FILE_EXTENSION - ) + outfile_local = f"{outroot_local}_{label}{ig:03d}_ev" + HEN_FILE_EXTENSION good_gti = cross_two_gtis([g], gti) if noclobber and os.path.exists(outfile_local): warnings.warn( - f"{outfile_local} exists, " - + "and noclobber option used. Skipping" + f"{outfile_local} exists, " + "and noclobber option used. Skipping" ) return good = np.logical_and(events.time >= g[0], events.time < g[1]) @@ -279,9 +272,7 @@ def join_eventlists(event_file1, event_file2, new_event_file=None, ignore_instr= Output event file """ if new_event_file is None: - new_event_file = ( - common_name(event_file1, event_file2) + "_ev" + HEN_FILE_EXTENSION - ) + new_event_file = common_name(event_file1, event_file2) + "_ev" + HEN_FILE_EXTENSION events1 = load_events(event_file1) events2 = load_events(event_file2) @@ -354,11 +345,7 @@ def join_many_eventlists(eventfiles, new_event_file=None, ignore_instr=False): if not np.isclose(events.mjdref, first_events.mjdref): warnings.warn(f"{event_file} has a different MJDREF") continue - if ( - hasattr(events, "instr") - and not events.instr == first_events.instr - and not ignore_instr - ): + if hasattr(events, "instr") and not events.instr == first_events.instr and not ignore_instr: warnings.warn(f"{event_file} is from a different instrument") continue elif ignore_instr: @@ -467,14 +454,11 @@ def main_join(args=None): import argparse description = ( - "Read a cleaned event files and saves the relevant " - "information in a standard format" + "Read a cleaned event files and saves the relevant " "information in a standard format" ) parser = argparse.ArgumentParser(description=description) parser.add_argument("files", help="Files to join", type=str, nargs="+") - parser.add_argument( - "-o", "--output", type=str, help="Name of output file", default=None - ) + parser.add_argument("-o", "--output", type=str, help="Name of output file", default=None) parser.add_argument( "--ignore-instr", help="Ignore instrument names in channels", @@ -518,8 +502,7 @@ def main_splitevents(args=None): parser.add_argument( "--overlap", type=float, - help="Overlap factor. 0 for no overlap, 0.5 for " - "half-interval overlap, and so on.", + help="Overlap factor. 0 for no overlap, 0.5 for " "half-interval overlap, and so on.", default=None, ) parser.add_argument( @@ -533,9 +516,7 @@ def main_splitevents(args=None): if args.split_at_mjd is not None: return split_eventlist_at_mjd(args.fname, mjd=args.split_at_mjd) - return split_eventlist( - args.fname, max_length=args.length_split, overlap=args.overlap - ) + return split_eventlist(args.fname, max_length=args.length_split, overlap=args.overlap) def main(args=None): @@ -546,8 +527,7 @@ def main(args=None): from .base import _add_default_args, check_negative_numbers_in_args description = ( - "Read a cleaned event files and saves the relevant " - "information in a standard format" + "Read a cleaned event files and saves the relevant " "information in a standard format" ) parser = argparse.ArgumentParser(description=description) parser.add_argument("files", help="List of files", nargs="+") diff --git a/hendrics/save_as_xspec.py b/hendrics/save_as_xspec.py index 3af93d45..c5b4809a 100644 --- a/hendrics/save_as_xspec.py +++ b/hendrics/save_as_xspec.py @@ -53,9 +53,7 @@ def save_as_xspec(fname, direct_save=False, save_lags=True): np.transpose([flo, fhi, lags * contents.df, lags_err * contents.df]), ) if direct_save: - sp.check_call( - f"flx2xsp {outname_lags} {outroot_lags}.pha {outroot_lags}.rsp".split() - ) + sp.check_call(f"flx2xsp {outname_lags} {outroot_lags}.pha {outroot_lags}.rsp".split()) def main(args=None): diff --git a/hendrics/sum_fspec.py b/hendrics/sum_fspec.py index 3f3c0acc..df817ee6 100644 --- a/hendrics/sum_fspec.py +++ b/hendrics/sum_fspec.py @@ -46,9 +46,7 @@ def main(args=None): "--outname", type=str, default=None, - help="Output file name for summed (C)PDS. Default:" - + " tot_(c)pds" - + HEN_FILE_EXTENSION, + help="Output file name for summed (C)PDS. Default:" + " tot_(c)pds" + HEN_FILE_EXTENSION, ) args = parser.parse_args(args) diff --git a/hendrics/timelags.py b/hendrics/timelags.py index a0cd482c..b561afb0 100644 --- a/hendrics/timelags.py +++ b/hendrics/timelags.py @@ -9,9 +9,7 @@ def main(args=None): from .base import _add_default_args - description = ( - "Read timelags from cross spectrum results and save them" " to a qdp file" - ) + description = "Read timelags from cross spectrum results and save them" " to a qdp file" parser = argparse.ArgumentParser(description=description) parser.add_argument("files", help="List of files", nargs="+") From 02adc07f0f8e37660c198cb26e73c3fd5801f513 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 13:10:19 +0200 Subject: [PATCH 23/58] Fix line style --- hendrics/tests/test_a_complete_run.py | 47 +++------- hendrics/tests/test_base.py | 4 +- hendrics/tests/test_binary.py | 27 ++---- hendrics/tests/test_calibrate.py | 20 ++--- hendrics/tests/test_colors.py | 20 ++--- hendrics/tests/test_efsearch.py | 16 +--- hendrics/tests/test_fake.py | 15 +--- hendrics/tests/test_ffa.py | 5 +- hendrics/tests/test_fspec.py | 124 ++++++++------------------ hendrics/tests/test_gti.py | 29 ++---- hendrics/tests/test_io.py | 8 +- hendrics/tests/test_lc.py | 61 ++++--------- hendrics/tests/test_phaseogram.py | 12 +-- hendrics/tests/test_phasetag.py | 26 +++--- hendrics/tests/test_read_events.py | 28 ++---- 15 files changed, 123 insertions(+), 319 deletions(-) diff --git a/hendrics/tests/test_a_complete_run.py b/hendrics/tests/test_a_complete_run.py index b1fe2c00..3bb02467 100644 --- a/hendrics/tests/test_a_complete_run.py +++ b/hendrics/tests/test_a_complete_run.py @@ -44,17 +44,11 @@ class TestFullRun: def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) - cls.ev_fileB = os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, @@ -70,12 +64,8 @@ def setup_class(cls): ) hen.read_events.main(command.split()) command = "{} {} -r {}".format( - os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ), - os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ), + os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), + os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "test.rmf"), ) hen.calibrate.main(command.split()) @@ -86,25 +76,17 @@ def setup_class(cls): os.path.join(cls.datadir, "monol_testB_E3-50_lc" + HEN_FILE_EXTENSION) ) command = ( - f"{cls.ev_fileAcal} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " - f"-o {cls.lcA}" + f"{cls.ev_fileAcal} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " f"-o {cls.lcA}" ) hen.lcurve.main(command.split()) command = ( - f"{cls.ev_fileBcal} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " - f"-o {cls.lcB}" + f"{cls.ev_fileBcal} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " f"-o {cls.lcB}" ) hen.lcurve.main(command.split()) - cls.pdsA = os.path.join( - cls.datadir, "monol_testA_E3-50_pds" + HEN_FILE_EXTENSION - ) - cls.pdsB = os.path.join( - cls.datadir, "monol_testB_E3-50_pds" + HEN_FILE_EXTENSION - ) - cls.cpds = os.path.join( - cls.datadir, "monol_test_E3-50_cpds" + HEN_FILE_EXTENSION - ) + cls.pdsA = os.path.join(cls.datadir, "monol_testA_E3-50_pds" + HEN_FILE_EXTENSION) + cls.pdsB = os.path.join(cls.datadir, "monol_testB_E3-50_pds" + HEN_FILE_EXTENSION) + cls.cpds = os.path.join(cls.datadir, "monol_test_E3-50_cpds" + HEN_FILE_EXTENSION) command = f"{cls.lcA} {cls.lcB} -f 128 -k PDS --save-all --norm leahy" hen.fspec.main(command.split()) @@ -207,9 +189,7 @@ def test_power_colors(self): def test_power_colors_2files(self): """Test light curve using PI filtering.""" # calculate colors - command = ( - f"--cross {self.ev_fileAcal} {self.ev_fileBcal} -s 16 -b -6 -f 1 2 4 8 16 " - ) + command = f"--cross {self.ev_fileAcal} {self.ev_fileBcal} -s 16 -b -6 -f 1 2 4 8 16 " with pytest.warns( UserWarning, match="(Some .non-log.)|(All power spectral)|(Poisson-subtracted)|(cast to real)", @@ -269,10 +249,7 @@ def test_plot_hid(self): ) hen.lcurve.main(command.split()) - lname = ( - os.path.join(self.datadir, "monol_testA_nustar_fpma_E3-10_lc") - + HEN_FILE_EXTENSION - ) + lname = os.path.join(self.datadir, "monol_testA_nustar_fpma_E3-10_lc") + HEN_FILE_EXTENSION os.path.exists(lname) cname = ( os.path.join(self.datadir, "monol_testA_nustar_fpma_E_10-5_over_5-3") diff --git a/hendrics/tests/test_base.py b/hendrics/tests/test_base.py index ac54107b..6cc0b1b4 100644 --- a/hendrics/tests/test_base.py +++ b/hendrics/tests/test_base.py @@ -60,9 +60,7 @@ def test_deorbit_badpar(): def test_deorbit_non_existing_par(): ev = np.asarray(1) - with pytest.raises( - FileNotFoundError, match="Parameter file warjladsfjqpeifjsdk.par" - ): + with pytest.raises(FileNotFoundError, match="Parameter file warjladsfjqpeifjsdk.par"): deorbit_events(ev, "warjladsfjqpeifjsdk.par") diff --git a/hendrics/tests/test_binary.py b/hendrics/tests/test_binary.py index 3bfe7290..2d44d281 100644 --- a/hendrics/tests/test_binary.py +++ b/hendrics/tests/test_binary.py @@ -33,30 +33,20 @@ class TestBinary: def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) - cls.ev_fileB = os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, ) cls.par = _dummy_par("bubububu.par") - command = "{0} --discard-calibration".format( - os.path.join(cls.datadir, "monol_testA.evt") - ) + command = "{0} --discard-calibration".format(os.path.join(cls.datadir, "monol_testA.evt")) hen.read_events.main(command.split()) command = "{} -r {}".format( - os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ), + os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "test.rmf"), ) hen.calibrate.main(command.split()) @@ -64,8 +54,7 @@ def setup_class(cls): os.path.join(cls.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) ) command = ( - f"{cls.ev_fileAcal} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " - f"-o {cls.lcA}" + f"{cls.ev_fileAcal} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " f"-o {cls.lcA}" ) hen.lcurve.main(command.split()) @@ -78,9 +67,7 @@ def test_save_binary_events(self): @pytest.mark.skipif("not HAS_PINT") def test_save_binary_calibrated_events(self): f = self.ev_fileAcal - hen.binary.main_presto( - f"{f} -b 0.1 -e 3 59 --debug --deorbit-par {self.par}".split() - ) + hen.binary.main_presto(f"{f} -b 0.1 -e 3 59 --debug --deorbit-par {self.par}".split()) assert os.path.exists(f.replace(HEN_FILE_EXTENSION, ".dat")) assert os.path.exists(f.replace(HEN_FILE_EXTENSION, ".inf")) diff --git a/hendrics/tests/test_calibrate.py b/hendrics/tests/test_calibrate.py index a18e9207..88574660 100644 --- a/hendrics/tests/test_calibrate.py +++ b/hendrics/tests/test_calibrate.py @@ -30,17 +30,11 @@ class TestCalibrate: def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) - cls.ev_fileB = os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, @@ -57,12 +51,8 @@ def setup_class(cls): ) hen.read_events.main(command.split()) command = "{} {} -r {} --nproc 2".format( - os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ), - os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ), + os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), + os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION), cls.rmf, ) hen.calibrate.main(command.split()) diff --git a/hendrics/tests/test_colors.py b/hendrics/tests/test_colors.py index bab91118..16c29c16 100644 --- a/hendrics/tests/test_colors.py +++ b/hendrics/tests/test_colors.py @@ -38,17 +38,11 @@ class TestFullRun: def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) - cls.ev_fileB = os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, @@ -65,12 +59,8 @@ def setup_class(cls): hen.read_events.main(command.split()) command = "{} {} -r {}".format( - os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ), - os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ), + os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), + os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "test.rmf"), ) hen.calibrate.main(command.split()) diff --git a/hendrics/tests/test_efsearch.py b/hendrics/tests/test_efsearch.py index ea6ba0fb..219c9b9c 100644 --- a/hendrics/tests/test_efsearch.py +++ b/hendrics/tests/test_efsearch.py @@ -75,9 +75,7 @@ def setup_class(cls): cls.dum_scramble = "events_scramble" + HEN_FILE_EXTENSION save_events(events, cls.dum) events_scramble = copy.deepcopy(events) - events_scramble.time = np.sort( - np.random.uniform(cls.tstart, cls.tend, events.time.size) - ) + events_scramble.time = np.sort(np.random.uniform(cls.tstart, cls.tend, events.time.size)) save_events(events_scramble, cls.dum_scramble) cls.par = "bububububu.par" _dummy_par(cls.par) @@ -131,9 +129,7 @@ def test_get_TOAs_template(self): def test_fit_profile_with_sinusoids(self): nbin = 32 phases = np.arange(0, 1, 1 / nbin) - prof_smooth = np.cos(2 * np.pi * phases) + 0.5 * np.cos( - 4 * np.pi * (phases + 0.5) - ) + prof_smooth = np.cos(2 * np.pi * phases) + 0.5 * np.cos(4 * np.pi * (phases + 0.5)) prof_smooth = (prof_smooth + 5) * 64 prof = np.random.poisson(prof_smooth) baseline = np.mean(prof) @@ -583,9 +579,7 @@ def test_zsearch_fdots_ffa(self): def test_fold_fast_fails(self): evfile = self.dum - with pytest.raises( - ValueError, match="The fast option is only available for z " - ): + with pytest.raises(ValueError, match="The fast option is only available for z "): main_efsearch([evfile, "-f", "9.85", "-F", "9.95", "-n", "64", "--fast"]) def test_zsearch_fdots_fast_transient(self): @@ -726,9 +720,7 @@ def test_accelsearch(self): def test_accelsearch_nodetections(self): evfile = self.dum_scramble with pytest.warns(UserWarning, match="The accelsearch functionality"): - outfile = main_accelsearch( - [evfile, "--fmin", "1", "--fmax", "1.1", "--zmax", "1"] - ) + outfile = main_accelsearch([evfile, "--fmin", "1", "--fmax", "1.1", "--zmax", "1"]) assert os.path.exists(outfile) os.unlink(outfile) diff --git a/hendrics/tests/test_fake.py b/hendrics/tests/test_fake.py index 8bea27ab..8ba4715d 100644 --- a/hendrics/tests/test_fake.py +++ b/hendrics/tests/test_fake.py @@ -52,8 +52,7 @@ def test_filter_for_deadtime_par(): """Test dead time filter, paralyzable case.""" events = np.array([1, 1.1, 2, 2.2, 3, 3.1, 3.2]) assert np.all( - hen.fake.filter_for_deadtime(events, 0.11, paralyzable=True) - == np.array([1, 2, 2.2, 3]) + hen.fake.filter_for_deadtime(events, 0.11, paralyzable=True) == np.array([1, 2, 2.2, 3]) ) @@ -157,9 +156,7 @@ def setup_class(cls): hen.read_events.main(command.split()) cls.first_event_file_cal = "calibrated" + HEN_FILE_EXTENSION - hen.calibrate.calibrate( - cls.first_event_file, cls.first_event_file_cal, rough=True - ) + hen.calibrate.calibrate(cls.first_event_file, cls.first_event_file_cal, rough=True) cls.xmm_fits_file = os.path.join(cls.datadir, "monol_test_fake_lc_xmm.evt") # Note that I don't specify the instrument. This is because @@ -299,9 +296,7 @@ def test_scramble_events(self): # Put exactly one photon inside a very short GTI times[0] = 0.5 times = np.sort(times) - event_list = EventList( - times, gti=np.array([[0, 0.9], [111, 123.2], [125.123, 1000]]) - ) + event_list = EventList(times, gti=np.array([[0, 0.9], [111, 123.2], [125.123, 1000]])) new_event_list = scramble(event_list, "smooth") assert new_event_list.time.size == times.size @@ -314,9 +309,7 @@ def test_scramble_events(self): def test_calibrate_xmm(self): """Test event file calibration.""" xmm_file = self.xmm_ev_file - command = "{0} -r {1} --nproc 2".format( - xmm_file, os.path.join(self.datadir, "test.rmf") - ) + command = "{0} -r {1} --nproc 2".format(xmm_file, os.path.join(self.datadir, "test.rmf")) with pytest.raises(RuntimeError): hen.calibrate.main(command.split()) diff --git a/hendrics/tests/test_ffa.py b/hendrics/tests/test_ffa.py index 1705c683..b39c3d13 100644 --- a/hendrics/tests/test_ffa.py +++ b/hendrics/tests/test_ffa.py @@ -1,9 +1,10 @@ import numpy as np -from stingray.efsearch import fit from stingray.events import EventList -from stingray.ffa import ffa_search from stingray.lightcurve import Lightcurve +from hendrics.efsearch import fit +from hendrics.ffa import ffa_search + # @pytest.mark.skipif('not HAS_NUMBA') def test_ffa(): diff --git a/hendrics/tests/test_fspec.py b/hendrics/tests/test_fspec.py index ee0689b0..0732aa2c 100644 --- a/hendrics/tests/test_fspec.py +++ b/hendrics/tests/test_fspec.py @@ -50,9 +50,7 @@ def test_cpds_fails_noclobber_exists(): def test_distributed_pds(): - events = EventList( - np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]]) - ) + events = EventList(np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]])) if hasattr(stingray.AveragedPowerspectrum, "from_events"): single_periodogram = stingray.AveragedPowerspectrum( events, @@ -76,12 +74,8 @@ def test_distributed_pds(): def test_distributed_cpds(): - events1 = EventList( - np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]]) - ) - events2 = EventList( - np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]]) - ) + events1 = EventList(np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]])) + events2 = EventList(np.sort(np.random.uniform(0, 1000, 1000)), gti=np.asarray([[0.0, 1000]])) if hasattr(stingray.AveragedCrossspectrum, "from_events"): single_periodogram = stingray.AveragedCrossspectrum( events1, @@ -96,9 +90,7 @@ def test_distributed_cpds(): events1, events2, segment_size=100, dt=0.1, norm="leahy" ) - pds_iterable = hen.fspec._provide_cross_periodograms( - events1, events2, 100, 0.1, "leahy" - ) + pds_iterable = hen.fspec._provide_cross_periodograms(events1, events2, 100, 0.1, "leahy") pds_distr = hen.fspec.average_periodograms(pds_iterable) assert np.allclose(pds_distr.power, single_periodogram.power) assert np.allclose(pds_distr.freq, single_periodogram.freq) @@ -123,12 +115,8 @@ def setup_class(cls): cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) - cls.ev_fileB = os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) for fname in [cls.ev_fileA, cls.ev_fileB]: if os.path.exists(fname): os.unlink(fname) @@ -176,8 +164,7 @@ def test_pds_leahy_emax_only(self): out = os.path.join( self.datadir, - f"monol_testA_nustar_fpma_{HENDRICS_STAR_VALUE}-50keV_pds" - + HEN_FILE_EXTENSION, + f"monol_testA_nustar_fpma_{HENDRICS_STAR_VALUE}-50keV_pds" + HEN_FILE_EXTENSION, ) assert os.path.exists(out) io.remove_pds(out) @@ -191,8 +178,7 @@ def test_pds_leahy_emin_only(self): out = os.path.join( self.datadir, - f"monol_testA_nustar_fpma_3-{HENDRICS_STAR_VALUE}keV_pds" - + HEN_FILE_EXTENSION, + f"monol_testA_nustar_fpma_3-{HENDRICS_STAR_VALUE}keV_pds" + HEN_FILE_EXTENSION, ) assert os.path.exists(out) io.remove_pds(out) @@ -246,11 +232,7 @@ def test_cpds_leahy_lombscargle(self): command = f"{evdata1} {evdata2} -k CPDS --norm leahy --lombscargle -b -1" hen.fspec.main(command.split()) - evout = ( - evdata1.replace("fpma", "fpm") - .replace("testA", "test") - .replace("_ev", "_LS_cpds") - ) + evout = evdata1.replace("fpma", "fpm").replace("testA", "test").replace("_ev", "_LS_cpds") assert os.path.exists(evout) evpds = hen.io.load_pds(evout) io.remove_pds(evout) @@ -287,12 +269,8 @@ def test_pds(self, data_kind, lombscargle): else: label = "_lc" - outA = os.path.join( - self.datadir, "monol_testA_nustar_fpma_pds" + HEN_FILE_EXTENSION - ) - outB = os.path.join( - self.datadir, "monol_testB_nustar_fpmb_pds" + HEN_FILE_EXTENSION - ) + outA = os.path.join(self.datadir, "monol_testA_nustar_fpma_pds" + HEN_FILE_EXTENSION) + outB = os.path.join(self.datadir, "monol_testB_nustar_fpmb_pds" + HEN_FILE_EXTENSION) if lombscargle: outA = outA.replace("pds", "LS_pds") outB = outB.replace("pds", "LS_pds") @@ -306,10 +284,8 @@ def test_pds(self, data_kind, lombscargle): opts += " --lombscargle" command = "{0} {1} {2}".format( opts, - os.path.join(self.datadir, f"monol_testA_nustar_fpma{label}") - + HEN_FILE_EXTENSION, - os.path.join(self.datadir, f"monol_testB_nustar_fpmb{label}") - + HEN_FILE_EXTENSION, + os.path.join(self.datadir, f"monol_testA_nustar_fpma{label}") + HEN_FILE_EXTENSION, + os.path.join(self.datadir, f"monol_testB_nustar_fpmb{label}") + HEN_FILE_EXTENSION, ) hen.fspec.main(command.split()) @@ -338,18 +314,12 @@ def test_ignore_gti(self, data_kind): label = "_lc" command = "{0} {1} -f 128 --ignore-gtis".format( - os.path.join(self.datadir, f"monol_testA_nustar_fpma{label}") - + HEN_FILE_EXTENSION, - os.path.join(self.datadir, f"monol_testB_nustar_fpmb{label}") - + HEN_FILE_EXTENSION, + os.path.join(self.datadir, f"monol_testA_nustar_fpma{label}") + HEN_FILE_EXTENSION, + os.path.join(self.datadir, f"monol_testB_nustar_fpmb{label}") + HEN_FILE_EXTENSION, ) hen.fspec.main(command.split()) - outA = os.path.join( - self.datadir, "monol_testA_nustar_fpma_pds" + HEN_FILE_EXTENSION - ) - outB = os.path.join( - self.datadir, "monol_testB_nustar_fpmb_pds" + HEN_FILE_EXTENSION - ) + outA = os.path.join(self.datadir, "monol_testA_nustar_fpma_pds" + HEN_FILE_EXTENSION) + outB = os.path.join(self.datadir, "monol_testB_nustar_fpmb_pds" + HEN_FILE_EXTENSION) assert os.path.exists(outA) assert os.path.exists(outB) os.unlink(outA) @@ -383,12 +353,10 @@ def test_cpds_ignore_instr(self): def test_cpds_rms_norm(self): """Test CPDS production.""" - command = ( - "{0} {1} -f 128 --save-dyn -k CPDS --save-all " "--norm rms -o {2}".format( - self.lcA, - self.lcB, - os.path.join(self.datadir, "monol_test_3-50keV_rms"), - ) + command = "{0} {1} -f 128 --save-dyn -k CPDS --save-all " "--norm rms -o {2}".format( + self.lcA, + self.lcB, + os.path.join(self.datadir, "monol_test_3-50keV_rms"), ) hen.fspec.main(command.split()) @@ -405,12 +373,10 @@ def test_cpds_wrong_norm(self): def test_cpds_dtbig(self): """Test CPDS production.""" - command = ( - "{0} {1} -f 128 --save-dyn -k CPDS --save-all --norm " "frac -o {2}".format( - self.lcA, - self.lcB, - os.path.join(self.datadir, "monol_test_3-50keV_dtb"), - ) + command = "{0} {1} -f 128 --save-dyn -k CPDS --save-all --norm " "frac -o {2}".format( + self.lcA, + self.lcB, + os.path.join(self.datadir, "monol_test_3-50keV_dtb"), ) command += " -b 1" hen.fspec.main(command.split()) @@ -441,9 +407,7 @@ def test_sumpds(self): def test_dumpdyncpds(self): """Test dump dynamical PDSs.""" command = ( - "--noplot " - + os.path.join(self.datadir, "monol_test_3-50keV_cpds") - + HEN_FILE_EXTENSION + "--noplot " + os.path.join(self.datadir, "monol_test_3-50keV_cpds") + HEN_FILE_EXTENSION ) with pytest.raises(NotImplementedError): hen.fspec.dumpdyn_main(command.split()) @@ -451,8 +415,7 @@ def test_dumpdyncpds(self): def test_rebinpds(self): """Test PDS rebinning 1.""" command = "{0} -r 2".format( - os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds") - + HEN_FILE_EXTENSION + os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds") + HEN_FILE_EXTENSION ) hen.rebin.main(command.split()) os.path.exists( @@ -465,10 +428,8 @@ def test_rebinpds(self): def test_rebinpds_geom(self): """Test geometrical PDS rebinning.""" command = "{0} {1} -r 1.03".format( - os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds") - + HEN_FILE_EXTENSION, - os.path.join(self.datadir, "monol_testB_nustar_fpmb_3-50keV_pds") - + HEN_FILE_EXTENSION, + os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds") + HEN_FILE_EXTENSION, + os.path.join(self.datadir, "monol_testB_nustar_fpmb_3-50keV_pds") + HEN_FILE_EXTENSION, ) hen.rebin.main(command.split()) os.path.exists( @@ -487,8 +448,7 @@ def test_rebinpds_geom(self): def test_rebincpds(self): """Test CPDS rebinning.""" command = "{0} -r 2".format( - os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") - + HEN_FILE_EXTENSION + os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") + HEN_FILE_EXTENSION ) hen.rebin.main(command.split()) os.path.exists( @@ -501,8 +461,7 @@ def test_rebincpds(self): def test_rebincpds_geom(self): """Test CPDS geometrical rebinning.""" command = "{0} -r 1.03".format( - os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") - + HEN_FILE_EXTENSION + os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") + HEN_FILE_EXTENSION ) hen.rebin.main(command.split()) os.path.exists( @@ -541,12 +500,8 @@ def test_fit_pds(self): command = f"{pdsfile1} {pdsfile2} -m {modelfile} --frequency-interval 0 10" hen.modeling.main_model(command.split()) - out0 = os.path.join( - self.datadir, "monol_testA_nustar_fpma_3-50keV_pds_bestfit.p" - ) - out1 = os.path.join( - self.datadir, "monol_testB_nustar_fpmb_3-50keV_pds_bestfit.p" - ) + out0 = os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds_bestfit.p") + out1 = os.path.join(self.datadir, "monol_testB_nustar_fpmb_3-50keV_pds_bestfit.p") assert os.path.exists(out0) assert os.path.exists(out1) m, k, c = hen.io.load_model( @@ -587,9 +542,7 @@ def test_fit_cpds(self): with pytest.warns(ComplexWarning): hen.modeling.main_model(command.split()) - out0 = os.path.join( - self.datadir, "monol_test_nustar_fpm_3-50keV_cpds_bestfit.p" - ) + out0 = os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds_bestfit.p") assert os.path.exists(out0) m, k, c = hen.io.load_model(out0) assert hasattr(m, "amplitude") @@ -631,9 +584,7 @@ def test_savexspec(self): + HEN_FILE_EXTENSION ) hen.save_as_xspec.main(command.split()) - os.path.exists( - os.path.join(self.datadir, "monol_testA_nustar_fpmb_3-50keV_pds_rebin2.pha") - ) + os.path.exists(os.path.join(self.datadir, "monol_testA_nustar_fpmb_3-50keV_pds_rebin2.pha")) def test_savexspec_geom(self): """Test save as Xspec 2.""" @@ -666,10 +617,7 @@ def test_plot_lin(self): os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds_fit") + HEN_FILE_EXTENSION ) - lname = ( - os.path.join(self.datadir, "monol_testA_nustar_fpma_lc") - + HEN_FILE_EXTENSION - ) + lname = os.path.join(self.datadir, "monol_testA_nustar_fpma_lc") + HEN_FILE_EXTENSION hen.plot.main( [ pname, diff --git a/hendrics/tests/test_gti.py b/hendrics/tests/test_gti.py index cd5db1c3..11d72f77 100644 --- a/hendrics/tests/test_gti.py +++ b/hendrics/tests/test_gti.py @@ -35,17 +35,11 @@ class TestFullRun: def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) cls.par = _dummy_par("bubububu.par") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) - cls.ev_fileB = os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, @@ -64,12 +58,8 @@ def setup_class(cls): cls.ev_fileA, cls.ev_fileB, os.path.join(cls.datadir, "test.rmf") ) hen.calibrate.main(command.split()) - cls.lcA = os.path.join( - os.path.join(cls.datadir, "monol_testA_lc" + HEN_FILE_EXTENSION) - ) - cls.lcB = os.path.join( - os.path.join(cls.datadir, "monol_testB_lc" + HEN_FILE_EXTENSION) - ) + cls.lcA = os.path.join(os.path.join(cls.datadir, "monol_testA_lc" + HEN_FILE_EXTENSION)) + cls.lcB = os.path.join(os.path.join(cls.datadir, "monol_testB_lc" + HEN_FILE_EXTENSION)) command = f"{cls.ev_fileAcal} --nproc 2 -b 2 " f"-o {cls.lcA}" hen.lcurve.main(command.split()) command = f"{cls.ev_fileBcal} --nproc 2 -b 2 " f"-o {cls.lcB}" @@ -77,10 +67,7 @@ def setup_class(cls): command = f"{cls.ev_fileA} -f time>0 -c --debug" hen.create_gti.main(command.split()) - cls.gtifile = ( - os.path.join(cls.datadir, "monol_testA_nustar_fpma_gti") - + HEN_FILE_EXTENSION - ) + cls.gtifile = os.path.join(cls.datadir, "monol_testA_nustar_fpma_gti") + HEN_FILE_EXTENSION def test_create_gti(self): """Test creating a GTI file.""" @@ -90,9 +77,7 @@ def test_apply_gti(self): """Test applying a GTI file.""" fname = self.gtifile lcfname = self.ev_fileA - lcoutname = self.ev_fileA.replace( - HEN_FILE_EXTENSION, "_gtifilt" + HEN_FILE_EXTENSION - ) + lcoutname = self.ev_fileA.replace(HEN_FILE_EXTENSION, "_gtifilt" + HEN_FILE_EXTENSION) command = f"{lcfname} -a {fname} --debug" hen.create_gti.main(command.split()) hen.io.load_events(lcoutname) diff --git a/hendrics/tests/test_io.py b/hendrics/tests/test_io.py index d06e710e..a624785c 100644 --- a/hendrics/tests/test_io.py +++ b/hendrics/tests/test_io.py @@ -359,9 +359,7 @@ def test_load_and_save_cpds_all(self, fmt): pds.lc1 = Lightcurve(np.arange(2), [1, 2]) pds.lc2 = [Lightcurve(np.arange(2), [1, 2]), Lightcurve(np.arange(2), [3, 4])] - with pytest.warns( - UserWarning, match="Saving multiple light curves is not supported" - ): + with pytest.warns(UserWarning, match="Saving multiple light curves is not supported"): save_pds(pds, "bubup" + fmt, save_all=True) pds2 = load_pds("bubup" + fmt) for attr in [ @@ -615,9 +613,7 @@ def test_load_python_model_Astropy(self): def test_load_model_input_not_string(self): """Input is not a string""" - with pytest.raises( - TypeError, match="modelstring has to be an existing file name" - ): + with pytest.raises(TypeError, match="modelstring has to be an existing file name"): b, kind, _ = load_model(1) def test_load_model_input_file_doesnt_exist(self): diff --git a/hendrics/tests/test_lc.py b/hendrics/tests/test_lc.py index 8822bc38..e686c449 100644 --- a/hendrics/tests/test_lc.py +++ b/hendrics/tests/test_lc.py @@ -46,9 +46,7 @@ def test_treat_event_file_nustar(self): treat_event_file(self.fits_fileA, discard_calibration=True) lcurve_from_events(self.new_filename) - newfile = os.path.join( - self.datadir, "monol_testA_nustar_fpma_lc" + HEN_FILE_EXTENSION - ) + newfile = os.path.join(self.datadir, "monol_testA_nustar_fpma_lc" + HEN_FILE_EXTENSION) assert os.path.exists(newfile) type, data = get_file_type(newfile) assert type == "lc" @@ -97,12 +95,8 @@ def setup_class(cls): curdir = os.path.abspath(os.path.dirname(__file__)) cls.datadir = os.path.join(curdir, "data") - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) - cls.ev_fileB = os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) cls.ev_fileAcal = os.path.join( cls.datadir, "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, @@ -118,12 +112,8 @@ def setup_class(cls): ) hen.read_events.main(command.split()) command = "{} {} -r {}".format( - os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ), - os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ), + os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), + os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "test.rmf"), ) hen.calibrate.main(command.split()) @@ -217,17 +207,13 @@ def test_fits_lcurve0(self): """Test light curves from FITS.""" lcurve_ftools_orig = os.path.join(self.datadir, "lcurveA.fits") - lcurve_ftools = os.path.join( - self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION - ) + lcurve_ftools = os.path.join(self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION) command = "{0} --outfile {1}".format( self.ev_fileAcal, os.path.join(self.datadir, "lcurve_lc") ) hen.lcurve.main(command.split()) - assert os.path.exists( - os.path.join(self.datadir, "lcurve_lc") + HEN_FILE_EXTENSION - ) + assert os.path.exists(os.path.join(self.datadir, "lcurve_lc") + HEN_FILE_EXTENSION) command = f"--fits-input {lcurve_ftools_orig} --outfile {lcurve_ftools}" hen.lcurve.main(command.split()) @@ -237,9 +223,7 @@ def test_fits_lcurve0(self): def test_fits_lcurve1(self): """Test light curves from FITS.""" - lcurve_ftools = os.path.join( - self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION - ) + lcurve_ftools = os.path.join(self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION) lcurve_mp = os.path.join(self.datadir, "lcurve_lc" + HEN_FILE_EXTENSION) @@ -255,9 +239,7 @@ def test_fits_lcurve1(self): diff = lc_mp[:goodlen] - lc_ftools[:goodlen] - assert np.all( - np.abs(diff) <= 1e-3 - ), "Light curve data do not coincide between FITS and HEN" + assert np.all(np.abs(diff) <= 1e-3), "Light curve data do not coincide between FITS and HEN" def test_txt_lcurve(self): """Test light curves from txt.""" @@ -287,9 +269,7 @@ def test_txt_lcurve(self): def test_joinlcs(self): """Test produce joined light curves.""" - new_filename = os.path.join( - self.datadir, "monol_test_joinlc" + HEN_FILE_EXTENSION - ) + new_filename = os.path.join(self.datadir, "monol_test_joinlc" + HEN_FILE_EXTENSION) # because join_lightcurves separates by instrument new_actual_filename = os.path.join( self.datadir, "fpmamonol_test_joinlc" + HEN_FILE_EXTENSION @@ -343,9 +323,7 @@ def testbaselinelc_nooutroot(self): command = f"{a_in} -p 0.001 --lam 1e5" hen.lcurve.baseline_main(command.split()) - out_lc = hen.io.load_lcurve( - hen.base.hen_root(a_in) + "_lc_baseline" + HEN_FILE_EXTENSION - ) + out_lc = hen.io.load_lcurve(hen.base.hen_root(a_in) + "_lc_baseline" + HEN_FILE_EXTENSION) assert hasattr(out_lc, "base") gti_to_test = hen.io.load_events(self.ev_fileA).gti assert np.allclose(gti_to_test, out_lc.gti) @@ -416,13 +394,8 @@ def test_create_gti_lc(self): def test_apply_gti_lc(self): """Test applying a GTI file.""" fname = os.path.join(self.datadir, "monol_testA_E3-50_gti") + HEN_FILE_EXTENSION - lcfname = ( - os.path.join(self.datadir, "monol_testA_E3-50_lc") + HEN_FILE_EXTENSION - ) - lcoutname = ( - os.path.join(self.datadir, "monol_testA_E3-50_lc_gtifilt") - + HEN_FILE_EXTENSION - ) + lcfname = os.path.join(self.datadir, "monol_testA_E3-50_lc") + HEN_FILE_EXTENSION + lcoutname = os.path.join(self.datadir, "monol_testA_E3-50_lc_gtifilt") + HEN_FILE_EXTENSION command = f"{lcfname} -a {fname} --debug" hen.create_gti.main(command.split()) hen.io.load_lcurve(lcoutname) @@ -437,9 +410,7 @@ def test_plot_lcurve_baseline(self): def test_pds_fits(self): """Test PDS production with light curves obtained from FITS files.""" - lcurve_ftools = os.path.join( - self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION - ) + lcurve_ftools = os.path.join(self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION) command = f"{lcurve_ftools} --save-all -f 128" hen.fspec.main(command.split()) @@ -456,9 +427,7 @@ def test_exposure(self): command = f"{lcname} {ufname}" hen.exposure.main(command.split()) - fname = os.path.join( - self.datadir, "monol_testA_E3-50_lccorr" + HEN_FILE_EXTENSION - ) + fname = os.path.join(self.datadir, "monol_testA_E3-50_lccorr" + HEN_FILE_EXTENSION) assert os.path.exists(fname) ftype, contents = hen.io.get_file_type(fname) diff --git a/hendrics/tests/test_phaseogram.py b/hendrics/tests/test_phaseogram.py index 4f791d39..f914b0bd 100644 --- a/hendrics/tests/test_phaseogram.py +++ b/hendrics/tests/test_phaseogram.py @@ -128,9 +128,7 @@ def test_phaseogram_input_periodogram(self, label): ] ) - @pytest.mark.parametrize( - "norm", ["to1", "mediansub", "mediannorm", "meansub", "meannorm"] - ) + @pytest.mark.parametrize("norm", ["to1", "mediansub", "mediannorm", "meansub", "meannorm"]) def test_phaseogram_input_norm(self, norm): evfile = self.dum main_phaseogram( @@ -205,9 +203,7 @@ def test_phaseogram_deorbit(self, withfX): withbt = not withfX create_parfile(par, withfX=withfX, withell1=withell1, withbt=withbt) - ip = run_interactive_phaseogram( - evfile, 9.9, test=True, nbin=16, nt=8, deorbit_par=par - ) + ip = run_interactive_phaseogram(evfile, 9.9, test=True, nbin=16, nt=8, deorbit_par=par) ip.update(1) with warnings.catch_warnings(record=True) as ws: ip.recalculate(1) @@ -280,9 +276,7 @@ def test_phaseogram_input_f_change_binary_deorbit(self, use_ell1): evfile = self.dum par = "orbit.par" create_parfile(par, withell1=use_ell1, withbt=not use_ell1) - ip = run_interactive_phaseogram( - evfile, 9.9, test=True, binary=True, deorbit_par=par - ) + ip = run_interactive_phaseogram(evfile, 9.9, test=True, binary=True, deorbit_par=par) ip.update(1) with warnings.catch_warnings(record=True) as ws: ip.recalculate(1) diff --git a/hendrics/tests/test_phasetag.py b/hendrics/tests/test_phasetag.py index 5e6effd0..a74a3d3e 100644 --- a/hendrics/tests/test_phasetag.py +++ b/hendrics/tests/test_phasetag.py @@ -1,10 +1,10 @@ -import os +from pathlib import Path import numpy as np import pytest -from stingray.phasetag import main_phasetag from astropy.io import fits +from hendrics.phasetag import main_phasetag from . import cleanup_test_dir @@ -14,9 +14,9 @@ class TestPhasetag: @classmethod def setup_class(cls): - curdir = os.path.abspath(os.path.dirname(__file__)) - cls.datadir = os.path.join(curdir, "data") - cls.fits_fileA = os.path.join(cls.datadir, "monol_testA.evt") + curdir = Path(__file__).resolve().parent + cls.datadir = Path(curdir, "data") + cls.fits_fileA = Path(cls.datadir, "monol_testA.evt") cls.freq = 0.1235242 @pytest.mark.parametrize("N", [5, 6, 11, 16, 32, 41]) @@ -33,8 +33,8 @@ def test_phase_tag(self, N): "--plot", ] ) - self.phasetagged = self.fits_fileA.replace(".evt", "_phasetag.evt") - assert os.path.exists(self.phasetagged) + self.phasetagged = Path(str(self.fits_fileA).replace(".evt", "_phasetag.evt")) + assert self.phasetagged.exists() # Redo to test if existing columns are preserved main_phasetag( @@ -69,13 +69,13 @@ def test_phase_tag(self, N): # I used --tomax assert np.argmax(prof) == 0 - os.unlink(self.phasetagged) + self.phasetagged.unlink() @pytest.mark.parametrize("N", [5, 6, 11, 16, 32, 41]) def test_phase_tag_TOA(self, N): main_phasetag( [ - self.fits_fileA, + str(self.fits_fileA), "-f", str(self.freq), "--test", @@ -86,8 +86,8 @@ def test_phase_tag_TOA(self, N): "--plot", ] ) - self.phasetagged = self.fits_fileA.replace(".evt", "_phasetag.evt") - assert os.path.exists(self.phasetagged) + self.phasetagged = Path(str(self.fits_fileA).replace(".evt", "_phasetag.evt")) + assert self.phasetagged.exists() def test_phase_tag_badexposure(self): with pytest.warns(UserWarning, match="Exposure has NaNs or zeros. "): @@ -122,9 +122,7 @@ def test_phase_tag_invalid1(self): ) def test_phase_tag_parfile(self): - with pytest.raises( - NotImplementedError, match="This part is not yet implemented" - ): + with pytest.raises(NotImplementedError, match="This part is not yet implemented"): main_phasetag([self.fits_fileA, "--parfile", "bubu.par", "--test"]) @classmethod diff --git a/hendrics/tests/test_read_events.py b/hendrics/tests/test_read_events.py index 1fd95c57..8a391aeb 100644 --- a/hendrics/tests/test_read_events.py +++ b/hendrics/tests/test_read_events.py @@ -227,12 +227,8 @@ def setup_class(cls): cls.fits_file, ] ) - cls.ev_fileA = os.path.join( - cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) - cls.ev_fileB = os.path.join( - cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION - ) + cls.ev_fileA = os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) + cls.ev_fileB = os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION) def test_start(self): """Make any warnings in setup_class be dumped here.""" @@ -258,9 +254,7 @@ def test_treat_event_file_xmm(self): assert "pi" in data and data["pi"].size > 0 def test_treat_event_file_xte_se(self): - treat_event_file( - self.fits_file_xte, split_by_detector=False, bin_time_for_occultations=1 - ) + treat_event_file(self.fits_file_xte, split_by_detector=False, bin_time_for_occultations=1) new_filename = "xte_test_xte_pca_ev" + HEN_FILE_EXTENSION assert os.path.exists(os.path.join(self.datadir, new_filename)) data = load_data(os.path.join(self.datadir, new_filename)) @@ -319,9 +313,7 @@ def test_treat_event_file_xmm_lensplit(self): def test_split_events(self): treat_event_file(self.fits_fileA) - filea = os.path.join( - self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) + filea = os.path.join(self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) files = hen.read_events.main_splitevents([filea, "-l", "50"]) for f in files: @@ -330,16 +322,12 @@ def test_split_events(self): def test_split_events_at_mjd(self): treat_event_file(self.fits_fileA) - filea = os.path.join( - self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) + filea = os.path.join(self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) data = load_events(filea) mean_met = np.mean(data.time) mean_mjd = mean_met / 86400 + data.mjdref - files = hen.read_events.main_splitevents( - [filea, "--split-at-mjd", f"{mean_mjd}"] - ) + files = hen.read_events.main_splitevents([filea, "--split-at-mjd", f"{mean_mjd}"]) assert "before" in files[0] assert "after" in files[1] @@ -351,9 +339,7 @@ def test_split_events_at_mjd(self): def test_split_events_bad_overlap_raises(self): treat_event_file(self.fits_fileA) - filea = os.path.join( - self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION - ) + filea = os.path.join(self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) with pytest.raises(ValueError, match="Overlap cannot be >=1. Exiting."): hen.read_events.split_eventlist(filea, 10, overlap=1.5) From 8b514129f20ad733cae8e7e5b7551166513974dd Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 13:14:18 +0200 Subject: [PATCH 24/58] Reformat a lot --- hendrics/varenergy.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/hendrics/varenergy.py b/hendrics/varenergy.py index c607d962..daad14b2 100644 --- a/hendrics/varenergy.py +++ b/hendrics/varenergy.py @@ -158,9 +158,7 @@ def main(args=None): default=None, help="Reference band when relevant", ) - parser.add_argument( - "--rms", default=False, action="store_true", help="Calculate rms" - ) + parser.add_argument("--rms", default=False, action="store_true", help="Calculate rms") parser.add_argument( "--covariance", default=False, @@ -266,8 +264,7 @@ def main(args=None): if fname2 is not None: events2 = load_events(fname2) if not args.use_pi and ( - events.energy is None - or (events2 is not None and events2.energy is None) + events.energy is None or (events2 is not None and events2.energy is None) ): raise ValueError( "If --use-pi is not specified, event lists must " From 151a4eecf73bf7a389dcddde605a3516e025cd0d Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 13:15:14 +0200 Subject: [PATCH 25/58] Reformat a lot --- notebooks/deadtime_model_zhang.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/notebooks/deadtime_model_zhang.py b/notebooks/deadtime_model_zhang.py index 6f6eebdf..f36b0dc9 100644 --- a/notebooks/deadtime_model_zhang.py +++ b/notebooks/deadtime_model_zhang.py @@ -62,9 +62,7 @@ def h(k, n, td, tb, tau): @jit(nopython=True) def A(k, r0, td, tb, tau): if k == 0: - return ( - r0 * tb * (1 + 2 * sum([h(1, n, td, tb, tau) for n in range(1, INFINITE)])) - ) + return r0 * tb * (1 + 2 * sum([h(1, n, td, tb, tau) for n in range(1, INFINITE)])) eq39_sums = [ h(k + 1, n, td, tb, tau) - 2 * h(k, n, td, tb, tau) + h(k - 1, n, td, tb, tau) @@ -132,11 +130,7 @@ def pds_model_zhang_back(N, rate, td, tb, limit_k=60): for k in range(1, N) ] - P[j] = ( - 2 - / Nph - * (N * safe_A(0, r0, td, tb, tau, limit_k=limit_k) + 2 * sum(eq8_sums)) - ) + P[j] = 2 / Nph * (N * safe_A(0, r0, td, tb, tau, limit_k=limit_k) + 2 * sum(eq8_sums)) maxf = 0.5 / tb df = maxf / len(P) From eba55a12ae5c37c9f7ace6c3344c4c5a25d8739a Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 13:15:27 +0200 Subject: [PATCH 26/58] Reformat a lot --- docs/conf.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 08d7e702..29088402 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -32,9 +32,7 @@ try: from sphinx_astropy.conf.v1 import * # noqa except ImportError: - print( - "ERROR: the documentation requires the sphinx-astropy package to be installed" - ) + print("ERROR: the documentation requires the sphinx-astropy package to be installed") sys.exit(1) # Get configuration information from setup.cfg @@ -144,9 +142,7 @@ # 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 + " Documentation", author, "manual") -] +latex_documents = [("index", project + ".tex", project + " Documentation", author, "manual")] # -- Options for manual page output ------------------------------------------- @@ -201,11 +197,7 @@ scripts = dict(conf.items("options.entry_points"))["console_scripts"] scripts = dict( - [ - (l.strip() for l in line.split("=")) - for line in scripts.split("\n") - if line.strip() != "" - ] + [(l.strip() for l in line.split("=")) for line in scripts.split("\n") if line.strip() != ""] ) import subprocess as sp From 284f23edad0a03665c7eac2171af028bb0d8fe3b Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 13:16:03 +0200 Subject: [PATCH 27/58] fix line length --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index dbff6f0d..6db51fd9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -258,6 +258,7 @@ filterwarnings = [ [tool.ruff] lint.select = ["ALL"] +line-length = 100 exclude=[ "notebooks/*.ipynb", "*.svg" @@ -336,6 +337,8 @@ lint.ignore = [ # NOTE: non-permanent exclusions should be added to `.ruff.toml [tool.ruff.lint.extend-per-file-ignores] "setup.py" = ["INP001"] # Part of configuration, not a package. ".github/workflows/*.py" = ["INP001"] +"notebooks/*.py" = ["INP001"] + "test_*.py" = [ "ANN201", # Public function without return type annotation "B018", # UselessExpression From 006948b1c94808d86e0c276216a15b191e798673 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 13:16:21 +0200 Subject: [PATCH 28/58] Add many hooks --- .pre-commit-config.yaml | 97 ++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 44 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 211e730a..5e642432 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,7 +8,13 @@ repos: hooks: - id: check-added-large-files args: ["--enforce-all", "--maxkb=300"] - # exclude: + exclude: "^(\ + .*.svg|\ + notebooks/.*.ipynb|\ + .*.jpe?g|\ + .*logo.png|\ + .*test.rmf|\ + )$" # Prevent giant files from being committed. - id: check-case-conflict # Check for files with names that would conflict on a case-insensitive @@ -30,7 +36,7 @@ repos: # Checks for the existence of private keys. - id: end-of-file-fixer # Makes sure files end in a newline and only a newline. - exclude: ".*(data.*|extern.*|licenses.*|_static.*|_parsetab.py)$" + exclude: ".*(.*.svg|data.*|extern.*|_templates.*|licenses.*|_static.*|_parsetab.py)$" # - id: fix-encoding-pragma # covered by pyupgrade - id: trailing-whitespace # Trims trailing whitespace. @@ -46,6 +52,9 @@ repos: # Detect mistake of inline code touching normal text in rst. - id: text-unicode-replacement-char # Forbid files which have a UTF-8 Unicode replacement character. + exclude: "^(\ + .*.rmf|\ + )$" - repo: https://github.com/codespell-project/codespell rev: v2.3.0 @@ -62,47 +71,47 @@ repos: args: ["--fix", "--show-fixes"] - id: ruff-format - - repo: https://github.com/scientific-python/cookie - rev: 2024.08.19 - hooks: - - id: sp-repo-review + # - repo: https://github.com/scientific-python/cookie + # rev: 2024.08.19 + # hooks: + # - id: sp-repo-review - - repo: https://github.com/PyCQA/docformatter - # using an untagged rev for forward compatibility with pre-commit 4.0 - # see https://github.com/PyCQA/docformatter/issues/289 - # This should be changed back to a tag when (>1.7.5) is released - rev: 06907d0267368b49b9180eed423fae5697c1e909 - hooks: - - id: docformatter - additional_dependencies: [tomli] - args: [--in-place, --config, ./pyproject.toml] - exclude: | - (?x)( - test.*\.py | - hendrics/__init__\.py | - hendrics/_dev/ | - hendrics/conftest\.py | - astropy/version\.py | - docs/ | - examples/ - ) + # - repo: https://github.com/PyCQA/docformatter + # # using an untagged rev for forward compatibility with pre-commit 4.0 + # # see https://github.com/PyCQA/docformatter/issues/289 + # # This should be changed back to a tag when (>1.7.5) is released + # rev: 06907d0267368b49b9180eed423fae5697c1e909 + # hooks: + # - id: docformatter + # additional_dependencies: [tomli] + # args: [--in-place, --config, ./pyproject.toml] + # exclude: | + # (?x)( + # test.*\.py | + # hendrics/__init__\.py | + # hendrics/_dev/ | + # hendrics/conftest\.py | + # astropy/version\.py | + # docs/ | + # examples/ + # ) - - repo: local - hooks: - - id: changelogs-rst - name: changelog filenames - language: fail - entry: >- - changelog files must be named /####.(bugfix|feature|api|perf).rst - or ####.other.rst (in the root directory only) - exclude: >- - ^docs/changes/[\w\.]+/(\d+\.(bugfix|feature|api|perf)(\.\d)?.rst|.gitkeep) - files: ^docs/changes/[\w\.]+/ - - id: changelogs-rst-other - name: changelog filenames for other category - language: fail - entry: >- - only "other" changelog files must be placed in the root directory - exclude: >- - ^docs/changes/(\d+\.other.rst|README.rst|template.rst) - files: ^docs/changes/\d+.\w+.rst + # - repo: local + # hooks: + # - id: changelogs-rst + # name: changelog filenames + # language: fail + # entry: >- + # changelog files must be named /####.(bugfix|feature|api|perf).rst + # or ####.other.rst (in the root directory only) + # exclude: >- + # ^docs/changes/[\w\.]+/(\d+\.(bugfix|feature|api|perf)(\.\d)?.rst|.gitkeep) + # files: ^docs/changes/[\w\.]+/ + # - id: changelogs-rst-other + # name: changelog filenames for other category + # language: fail + # entry: >- + # only "other" changelog files must be placed in the root directory + # exclude: >- + # ^docs/changes/(\d+\.other.rst|README.rst|template.rst) + # files: ^docs/changes/\d+.\w+.rst From d425a1238555695ab3aa7536e9c5a3e932f2da34 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 13:39:22 +0200 Subject: [PATCH 29/58] Use pathlib --- setup.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 7940dc39..d88ba36c 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,10 @@ -#!/usr/bin/env python # Licensed under a 3-clause BSD style license - see LICENSE.rst # NOTE: The configuration for the package, including the name, version, and # other information are set in the setup.cfg file. -import os import sys +from pathlib import Path from setuptools import setup @@ -75,7 +74,7 @@ setup( use_scm_version={ - "write_to": os.path.join("hendrics", "version.py"), + "write_to": Path("hendrics", "version.py"), "write_to_template": VERSION_TEMPLATE, } ) From d7c2b22a73a5a637085055ab605888d65317cdf4 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 16:09:20 +0200 Subject: [PATCH 30/58] Allow paths in extension/splitext --- hendrics/base.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/hendrics/base.py b/hendrics/base.py index f6617bda..89eb8fed 100644 --- a/hendrics/base.py +++ b/hendrics/base.py @@ -3,7 +3,7 @@ import copy import os -import os.path +from pathlib import Path import sys import tempfile import urllib @@ -1267,12 +1267,12 @@ def get_file_extension(fname): >>> get_file_extension('bu.fits.Gz') '.fits.Gz' """ - raw_ext = os.path.splitext(fname)[1] - if raw_ext.lower() in [".gz", ".bz", ".z", ".bz2"]: - fname = fname.replace(raw_ext, "") - return os.path.splitext(fname)[1] + raw_ext - - return raw_ext + if not isinstance(fname, Path): + fname = Path(fname) + ext = fname.suffix + if ext.lower() in [".gz", ".bz", ".z", ".bz2"]: + ext = "".join(fname.suffixes[-2:]) + return ext def splitext_improved(fname): @@ -1290,9 +1290,15 @@ def splitext_improved(fname): ('bu', '.ecsv') >>> splitext_improved('bu.fits.Gz') ('bu', '.fits.Gz') + >>> path = splitext_improved(Path('bu.fits.Gz')) + >>> assert str(path[0]) == 'bu' + >>> assert path[1] == '.fits.Gz' """ + is_path = isinstance(fname, Path) ext = get_file_extension(fname) - root = fname.replace(ext, "") + root = str(fname).removesuffix(ext) + if is_path: + root = Path(root) return root, ext From 958efe90e72f742244026cefe88bcb0ad1c72a3d Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 16:50:54 +0200 Subject: [PATCH 31/58] Small fixes --- hendrics/base.py | 1 - hendrics/tests/test_io.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/hendrics/base.py b/hendrics/base.py index 89eb8fed..d0956613 100644 --- a/hendrics/base.py +++ b/hendrics/base.py @@ -3,7 +3,6 @@ import copy import os -from pathlib import Path import sys import tempfile import urllib diff --git a/hendrics/tests/test_io.py b/hendrics/tests/test_io.py index a624785c..577a16df 100644 --- a/hendrics/tests/test_io.py +++ b/hendrics/tests/test_io.py @@ -486,7 +486,7 @@ def test_save_longcomplex(self): assert np.allclose(data["val"], data_out["val"]) @pytest.mark.skipif("not HAS_C256 or not HAS_NETCDF") - def test_save_longcomplex(self): + def test_save_longcomplex_warns(self): val = np.complex256(1.01 + 2.3j) data = {"val": val} with pytest.warns(UserWarning, match="complex256 yet"): From dcd5648eb6a4c7b4a01a930b2b8f5fd8147d2358 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 21:18:50 +0200 Subject: [PATCH 32/58] Fix string formatting everywhere --- docs/conf.py | 4 +- hendrics/calibrate.py | 4 +- hendrics/fake.py | 2 +- hendrics/fspec.py | 14 +++--- hendrics/io.py | 22 ++++----- hendrics/lcurve.py | 18 +++---- hendrics/plot.py | 2 +- hendrics/read_events.py | 2 +- hendrics/rebin.py | 6 +-- hendrics/sum_fspec.py | 2 +- hendrics/tests/test_a_complete_run.py | 18 +++---- hendrics/tests/test_binary.py | 8 +++- hendrics/tests/test_calibrate.py | 7 ++- hendrics/tests/test_colors.py | 6 ++- hendrics/tests/test_fake.py | 3 +- hendrics/tests/test_fspec.py | 69 ++++++++++++--------------- hendrics/tests/test_gti.py | 7 ++- hendrics/tests/test_lc.py | 54 ++++++++------------- 18 files changed, 118 insertions(+), 130 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 29088402..c6efc6d9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -72,7 +72,7 @@ # This does not *have* to match the package name, but typically does project = setup_cfg["name"] author = setup_cfg["author"] -copyright = "{0}, {1}".format(datetime.datetime.now().year, setup_cfg["author"]) +copyright = f"{datetime.datetime.now().year}, {setup_cfg['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 @@ -165,7 +165,7 @@ edit_on_github_doc_root = "docs" # -- Resolving issue number to links in changelog ----------------------------- -github_issues_url = "https://github.com/{0}/issues/".format(setup_cfg["github_project"]) +github_issues_url = f"https://github.com/{setup_cfg['github_project']}/issues/" # -- Turn on nitpicky mode for sphinx (to warn about references not found) ---- # diff --git a/hendrics/calibrate.py b/hendrics/calibrate.py index ad933b86..d48843b1 100644 --- a/hendrics/calibrate.py +++ b/hendrics/calibrate.py @@ -144,7 +144,7 @@ def calibrate(fname, outname, rmf_file=None, rough=False): the one given by default_nustar_rmf() is used. """ # Read event file - log.info("Loading file %s..." % fname) + log.info(f"Loading file {fname}...") evdata = load_events(fname) log.info("Done.") pis = evdata.pi @@ -164,7 +164,7 @@ def calibrate(fname, outname, rmf_file=None, rough=False): es = read_calibration(pis, rmf_file) evdata.energy = es - log.info("Saving calibrated data to %s" % outname) + log.info(f"Saving calibrated data to {outname}") save_events(evdata, outname) diff --git a/hendrics/fake.py b/hendrics/fake.py index b36d6459..0e96dceb 100644 --- a/hendrics/fake.py +++ b/hendrics/fake.py @@ -248,7 +248,7 @@ def generate_fake_fits_observation( tbheader["TSTOP"] = (tstop, "Elapsed seconds since MJDREF at end of file") tbheader["LIVETIME"] = (livetime, "On-source time") tbheader["TIMEZERO"] = (0.000000e00, "Time Zero") - tbheader["HISTORY"] = "Generated with HENDRICS by {0}".format(os.getenv("USER")) + tbheader["HISTORY"] = f"Generated with HENDRICS by {os.getenv('USER')}" tbhdu = fits.BinTableHDU.from_columns(cols, header=tbheader) tbhdu.name = ext diff --git a/hendrics/fspec.py b/hendrics/fspec.py index abc87fb2..541dc1c6 100644 --- a/hendrics/fspec.py +++ b/hendrics/fspec.py @@ -314,7 +314,7 @@ def calc_pds( pds.back_phots = back_ctrate * fftlen pds.mjdref = mjdref - log.info("Saving PDS to %s" % outname) + log.info(f"Saving PDS to {outname}") save_pds( pds, outname, @@ -398,9 +398,9 @@ def calc_cpds( warnings.warn("File exists, and noclobber option used. Skipping") return - log.info("Loading file %s..." % lcfile1) + log.info(f"Loading file {lcfile1}...") ftype1, lc1 = get_file_type(lcfile1) - log.info("Loading file %s..." % lcfile2) + log.info(f"Loading file {lcfile2}...") ftype2, lc2 = get_file_type(lcfile2) instr1 = lc1.instr instr2 = lc2.instr @@ -467,7 +467,7 @@ def calc_cpds( cpds.lag = lags cpds.lag_err = lags_err - log.info("Saving CPDS to %s" % outname) + log.info(f"Saving CPDS to {outname}") save_pds( cpds, outname, @@ -551,8 +551,8 @@ def calc_fspec( [5] Miyamoto et al. 1991, ApJ, 383, 784 """ - log.info("Using %s normalization" % normalization) - log.info("Using %s processors" % nproc) + log.info(f"Using {normalization} normalization") + log.info(f"Using {nproc} processors") if do_calc_pds: wrapped_file_dicts = [] @@ -633,7 +633,7 @@ def calc_fspec( outr = outroot if len(files1) > 1 and outroot is None: - outr = common_name(f1, f2, default="%d" % i_f) + outr = common_name(f1, f2, default=f"{i_f}") if outr is not None: outname = os.path.join( diff --git a/hendrics/io.py b/hendrics/io.py index 6568032d..25da421e 100644 --- a/hendrics/io.py +++ b/hendrics/io.py @@ -898,7 +898,7 @@ def load_pds(fname, nosub=False): # ---- GENERIC function to save stuff. def _load_data_pickle(fname, kind="data"): """Load generic data in pickle format.""" - log.info("Loading %s and info from %s" % (kind, fname)) + log.info(f"Loading {kind} and info from {fname}") with open(fname, "rb") as fobj: result = pickle.load(fobj) return result @@ -906,7 +906,7 @@ def _load_data_pickle(fname, kind="data"): def _save_data_pickle(struct, fname, kind="data"): """Save generic data in pickle format.""" - log.info("Saving %s and info to %s" % (kind, fname)) + log.info(f"Saving {kind} and info to {fname}") with open(fname, "wb") as fobj: pickle.dump(struct, fobj) @@ -999,7 +999,7 @@ def _split_high_precision_number(varname, var, probesize): def _save_data_nc(struct, fname, kind="data"): """Save generic data in netcdf format.""" - log.info("Saving %s and info to %s" % (kind, fname)) + log.info(f"Saving {kind} and info to {fname}") varnames = [] values = [] formats = [] @@ -1044,7 +1044,7 @@ def _save_data_nc(struct, fname, kind="data"): varnames.append(k) else: values.append(var) - formats.append(probekind + "%d" % probesize) + formats.append(probekind + f"{probesize}") varnames.append(k) save_as_netcdf(values, varnames, formats, fname) @@ -1143,7 +1143,7 @@ def save_as_qdp(arrays, errors=None, filename="out.qdp", mode="w"): if print_header: for lerr in list_of_errs: i, kind = lerr - print("READ %s" % kind + "ERR %d" % (i + 1), file=outfile) + print(f"READ {kind}" + f"ERR {i + 1}", file=outfile) length = len(data_to_write[0]) for i in range(length): @@ -1168,7 +1168,7 @@ def save_as_ascii(cols, filename="out.txt", colnames=None, append=False): return -1 lcol = len(cols[0]) - log.debug("%s %s" % (repr(cols), repr(np.shape(cols)))) + log.debug(f"{repr(cols)} {repr(np.shape(cols))}") if append: txtfile = open(filename, "a") else: @@ -1216,12 +1216,12 @@ def print_fits_info(fits_file, hdu=1): start_mjd = Time(mjdref, format="mjd") + tstart * Unit(tunit) stop_mjd = Time(mjdref, format="mjd") + tstop * Unit(tunit) - print("ObsID: {0}\n".format(info["OBS_ID"])) - print("Date: {0} -- {1}\n".format(info["Start"], info["Stop"])) + print(f"ObsID: {info['OBS_ID']}\n") + print(f"Date: {info['Start']} -- {info['Stop']}\n") print(f"Date (MJD): {start_mjd} -- {stop_mjd}\n") - print("Instrument: {0}/{1}\n".format(info["Telescope"], info["Instrument"])) - print("Target: {0}\n".format(info["Target"])) - print("N. Events: {0}\n".format(info["N. events"])) + print(f"Instrument: {info['Telescope']}/{info['Instrument']}\n") + print(f"Target: {info['Target']}\n") + print(f"N. Events: {info["N. events"]}\n") lchdulist.close() return info diff --git a/hendrics/lcurve.py b/hendrics/lcurve.py index 92560f84..e14c99e5 100644 --- a/hendrics/lcurve.py +++ b/hendrics/lcurve.py @@ -116,7 +116,7 @@ def join_lightcurves(lcfilelist, outfile="out_lc" + HEN_FILE_EXTENSION): lcdatas = [] for lfc in lcfilelist: - log.info("Loading file %s..." % lfc) + log.info(f"Loading file {lfc}...") lcdata = load_lcurve(lfc) log.info("Done.") lcdatas.append(lcdata) @@ -131,7 +131,7 @@ def join_lightcurves(lcfilelist, outfile="out_lc" + HEN_FILE_EXTENSION): tag = "" else: tag = instr - log.info("Saving joined light curve to %s" % outfile) + log.info(f"Saving joined light curve to {outfile}") dname, fname = os.path.split(outfile) save_lcurve(outlcs[instr], os.path.join(dname, tag + fname)) @@ -226,7 +226,7 @@ def scrunch_lightcurves(lcfilelist, outfile="out_scrlc" + HEN_FILE_EXTENSION, sa lcdata = join_lightcurves(lcfilelist, outfile=None) lc0 = scrunch_lightcurve_objs(list(lcdata.values())) - log.info("Saving scrunched light curve to %s" % outfile) + log.info(f"Saving scrunched light curve to {outfile}") save_lcurve(lc0, outfile) return lc0 @@ -341,7 +341,7 @@ def lcurve_from_events( If True, do not overwrite existing files """ - log.info("Loading file %s..." % f) + log.info(f"Loading file {f}...") evdata = load_events(f) log.info("Done.") weight_on_tag = "" @@ -380,7 +380,7 @@ def lcurve_from_events( pis = evdata.pi good = np.logical_and(pis > pi_interval[0], pis <= pi_interval[1]) events = events[good] - tag = "_PI%g-%g" % (pi_interval[0], pi_interval[1]) + tag = f"_PI{pi_interval[0]}-{pi_interval[1]}" elif e_interval is not None and np.all(np.array(e_interval) > 0): if not hasattr(evdata, "energy") or evdata.energy is None: raise ValueError( @@ -389,7 +389,7 @@ def lcurve_from_events( es = evdata.energy good = np.logical_and(es > e_interval[0], es <= e_interval[1]) events = events[good] - tag = "_E%g-%g" % (e_interval[0], e_interval[1]) + tag = f"_E{e_interval[0]}-{e_interval[1]}" else: pass @@ -484,7 +484,7 @@ def lcurve_from_events( save_lcurve(l0, outf) outfiles.append(outf) else: - log.info("Saving light curve to %s" % outfile) + log.info(f"Saving light curve to {outfile}") save_lcurve(lc, outfile) outfiles = [outfile] @@ -690,7 +690,7 @@ def lcurve_from_fits( lc.instr = instr lc.header = lchdulist[ratehdu].header.tostring() - log.info("Saving light curve to %s" % outfile) + log.info(f"Saving light curve to {outfile}") save_lcurve(lc, outfile) return [outfile] @@ -759,7 +759,7 @@ def lcurve_from_txt( lc.instr = "EXTERN" - log.info("Saving light curve to %s" % outfile) + log.info(f"Saving light curve to {outfile}") save_lcurve(lc, outfile) return [outfile] diff --git a/hendrics/plot.py b/hendrics/plot.py index c16c27c0..68e6078d 100644 --- a/hendrics/plot.py +++ b/hendrics/plot.py @@ -769,7 +769,7 @@ def plot_lc( plt.figure("LC " + figlabel) for lcfile in lcfiles: - log.info("Loading %s..." % lcfile) + log.info(f"Loading {lcfile}...") lcdata = load_lcurve(lcfile) time = lcdata.time diff --git a/hendrics/read_events.py b/hendrics/read_events.py index 2cf8880a..64c094f3 100644 --- a/hendrics/read_events.py +++ b/hendrics/read_events.py @@ -65,7 +65,7 @@ def treat_event_file( counts per bin are significantly above 25 ct/s. """ # gtistring = assign_value_if_none(gtistring, "GTI,GTI0,STDGTI") - log.info("Opening %s" % filename) + log.info(f"Opening {filename}") events = EventList.read( filename, diff --git a/hendrics/rebin.py b/hendrics/rebin.py index 441ed8bb..0dc647d8 100644 --- a/hendrics/rebin.py +++ b/hendrics/rebin.py @@ -26,10 +26,8 @@ def rebin_file(filename, rebin): func = save_pds options = {"save_all": True} - outfile = filename.replace( - get_file_extension(filename), "_rebin%g" % rebin + HEN_FILE_EXTENSION - ) - log.info("Saving %s to %s" % (ftype, outfile)) + outfile = filename.replace(get_file_extension(filename), f"_rebin{rebin}" + HEN_FILE_EXTENSION) + log.info(f"Saving {ftype} to {outfile}") func(contents, outfile, **options) diff --git a/hendrics/sum_fspec.py b/hendrics/sum_fspec.py index df817ee6..0f70e854 100644 --- a/hendrics/sum_fspec.py +++ b/hendrics/sum_fspec.py @@ -26,7 +26,7 @@ def check_and_distribute_files(files): yield contents tot_contents = average_periodograms(check_and_distribute_files(files)) - log.info("Saving %s to %s" % (pdstype, outname)) + log.info(f"Saving {pdstype} to {outname}") save_pds(tot_contents, outname) return tot_contents diff --git a/hendrics/tests/test_a_complete_run.py b/hendrics/tests/test_a_complete_run.py index 3bb02467..4836209b 100644 --- a/hendrics/tests/test_a_complete_run.py +++ b/hendrics/tests/test_a_complete_run.py @@ -58,16 +58,19 @@ def setup_class(cls): "monol_testB_nustar_fpmb_ev_calib" + HEN_FILE_EXTENSION, ) cls.par = _dummy_par("bubububu.par") - command = "{0} {1} --discard-calibration".format( + data_a, data_b = ( os.path.join(cls.datadir, "monol_testA.evt"), os.path.join(cls.datadir, "monol_testB.evt"), ) + command = f"{data_a} {data_b} --discard-calibration" hen.read_events.main(command.split()) - command = "{} {} -r {}".format( + + data_a, data_b, rmf = ( os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "test.rmf"), ) + command = f"{data_a} {data_b} -r {rmf}" hen.calibrate.main(command.split()) cls.lcA = os.path.join( os.path.join(cls.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) @@ -239,14 +242,11 @@ def test_plot_color(self): def test_plot_hid(self): """Test plotting with linear axes.""" # also produce a light curve with the same binning - command = ("{0} -b 100 --energy-interval {1} {2}").format( - os.path.join( - self.datadir, - "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, - ), - 3, - 10, + data = os.path.join( + self.datadir, + "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, ) + command = f"{data} -b 100 --energy-interval 3 10" hen.lcurve.main(command.split()) lname = os.path.join(self.datadir, "monol_testA_nustar_fpma_E3-10_lc") + HEN_FILE_EXTENSION diff --git a/hendrics/tests/test_binary.py b/hendrics/tests/test_binary.py index 2d44d281..cb69deb5 100644 --- a/hendrics/tests/test_binary.py +++ b/hendrics/tests/test_binary.py @@ -43,13 +43,17 @@ def setup_class(cls): "monol_testA_nustar_fpma_ev_calib" + HEN_FILE_EXTENSION, ) cls.par = _dummy_par("bubububu.par") - command = "{0} --discard-calibration".format(os.path.join(cls.datadir, "monol_testA.evt")) + data = os.path.join(cls.datadir, "monol_testA.evt") + command = f"{data} --discard-calibration" hen.read_events.main(command.split()) - command = "{} -r {}".format( + + data, rmf = ( os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "test.rmf"), ) + command = f"{data} -r {rmf}" hen.calibrate.main(command.split()) + cls.lcA = os.path.join( os.path.join(cls.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) ) diff --git a/hendrics/tests/test_calibrate.py b/hendrics/tests/test_calibrate.py index 88574660..cafa18a5 100644 --- a/hendrics/tests/test_calibrate.py +++ b/hendrics/tests/test_calibrate.py @@ -45,16 +45,19 @@ def setup_class(cls): ) cls.par = _dummy_par("bubububu.par") cls.rmf = os.path.join(cls.datadir, "test.rmf") - command = "{0} {1} ".format( + data_a, data_b = ( os.path.join(cls.datadir, "monol_testA.evt"), os.path.join(cls.datadir, "monol_testB.evt"), ) + command = f"{data_a} {data_b} ".format() hen.read_events.main(command.split()) - command = "{} {} -r {} --nproc 2".format( + + data_a, data_b, rmf = ( os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION), cls.rmf, ) + command = f"{data_a} {data_b} -r {rmf} --nproc 2" hen.calibrate.main(command.split()) cls.xmm_fits_file = os.path.join(cls.datadir, "monol_test_fake_lc_xmm.evt") # Note that I don't specify the instrument. This is because diff --git a/hendrics/tests/test_colors.py b/hendrics/tests/test_colors.py index 16c29c16..b098338f 100644 --- a/hendrics/tests/test_colors.py +++ b/hendrics/tests/test_colors.py @@ -52,17 +52,19 @@ def setup_class(cls): "monol_testB_nustar_fpmb_ev_calib" + HEN_FILE_EXTENSION, ) cls.par = _dummy_par("bubububu.par") - command = "{0} {1} --discard-calibration".format( + data_a, data_b = ( os.path.join(cls.datadir, "monol_testA.evt"), os.path.join(cls.datadir, "monol_testB.evt"), ) + command = f"{data_a} {data_b} --discard-calibration" hen.read_events.main(command.split()) - command = "{} {} -r {}".format( + data_a, data_b, rmf = ( os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "test.rmf"), ) + command = f"{data_a} {data_b} -r {rmf}" hen.calibrate.main(command.split()) cls.lc3_10 = os.path.join( diff --git a/hendrics/tests/test_fake.py b/hendrics/tests/test_fake.py index 8ba4715d..a9584d7e 100644 --- a/hendrics/tests/test_fake.py +++ b/hendrics/tests/test_fake.py @@ -309,7 +309,8 @@ def test_scramble_events(self): def test_calibrate_xmm(self): """Test event file calibration.""" xmm_file = self.xmm_ev_file - command = "{0} -r {1} --nproc 2".format(xmm_file, os.path.join(self.datadir, "test.rmf")) + rmf = os.path.join(self.datadir, "test.rmf") + command = f"{xmm_file} -r {rmf} --nproc 2" with pytest.raises(RuntimeError): hen.calibrate.main(command.split()) diff --git a/hendrics/tests/test_fspec.py b/hendrics/tests/test_fspec.py index 0732aa2c..003c7cf1 100644 --- a/hendrics/tests/test_fspec.py +++ b/hendrics/tests/test_fspec.py @@ -122,10 +122,11 @@ def setup_class(cls): os.unlink(fname) cls.par = _dummy_par("bubububu.par") - command = "{0} {1}".format( + data_a, data_b = ( os.path.join(cls.datadir, "monol_testA.evt"), os.path.join(cls.datadir, "monol_testB.evt"), ) + command = f"{data_a} {data_b}" hen.read_events.main(command.split()) command = f"{cls.ev_fileA} {cls.ev_fileB} --nproc 2 -b -1" @@ -282,11 +283,11 @@ def test_pds(self, data_kind, lombscargle): opts = "-f 16 --save-all --save-dyn -k PDS -b 0.5 --norm frac" if lombscargle: opts += " --lombscargle" - command = "{0} {1} {2}".format( - opts, + data_a, data_b = ( os.path.join(self.datadir, f"monol_testA_nustar_fpma{label}") + HEN_FILE_EXTENSION, os.path.join(self.datadir, f"monol_testB_nustar_fpmb{label}") + HEN_FILE_EXTENSION, ) + command = f"{opts} {data_a} {data_b}" hen.fspec.main(command.split()) assert os.path.exists(outA) @@ -313,11 +314,13 @@ def test_ignore_gti(self, data_kind): else: label = "_lc" - command = "{0} {1} -f 128 --ignore-gtis".format( + data_a, data_b = ( os.path.join(self.datadir, f"monol_testA_nustar_fpma{label}") + HEN_FILE_EXTENSION, os.path.join(self.datadir, f"monol_testB_nustar_fpmb{label}") + HEN_FILE_EXTENSION, ) + command = f"{data_a} {data_b} -f 128 --ignore-gtis" hen.fspec.main(command.split()) + outA = os.path.join(self.datadir, "monol_testA_nustar_fpma_pds" + HEN_FILE_EXTENSION) outB = os.path.join(self.datadir, "monol_testB_nustar_fpmb_pds" + HEN_FILE_EXTENSION) assert os.path.exists(outA) @@ -330,54 +333,41 @@ def test_pds_events_big(self, kind): """Test PDS production.""" labelA = "nustar_fpma_ev" labelB = "nustar_fpmb_ev" - - command = "{0} {1} -f 16 -k {2} --norm frac --test".format( + data_a, data_b = ( os.path.join(self.datadir, f"monol_testA_{labelA}") + HEN_FILE_EXTENSION, os.path.join(self.datadir, f"monol_testB_{labelB}") + HEN_FILE_EXTENSION, - kind, ) + command = f"{data_a} {data_b} -f 16 -k {kind} --norm frac --test" hen.fspec.main(command.split()) def test_cpds_ignore_instr(self): """Test CPDS production.""" + out = os.path.join(self.datadir, "ignore_instr") + HEN_FILE_EXTENSION command = ( - "{0} {1} -f 128 --save-dyn -k CPDS,lag --save-all --ignore-instr" - " -o {2} --debug".format( - self.lcA, - self.lcB, - os.path.join(self.datadir, "ignore_instr") + HEN_FILE_EXTENSION, - ) + f"{self.lcA} {self.lcB} -f 128 --save-dyn -k CPDS,lag --save-all --ignore-instr" + f" -o {out} --debug" ) hen.fspec.main(command.split()) def test_cpds_rms_norm(self): """Test CPDS production.""" - command = "{0} {1} -f 128 --save-dyn -k CPDS --save-all " "--norm rms -o {2}".format( - self.lcA, - self.lcB, - os.path.join(self.datadir, "monol_test_3-50keV_rms"), - ) + out = os.path.join(self.datadir, "monol_test_3-50keV_rms") + command = f"{self.lcA} {self.lcB} -f 128 --save-dyn -k CPDS --save-all --norm rms -o {out}" hen.fspec.main(command.split()) def test_cpds_wrong_norm(self): """Test CPDS production.""" - command = "{0} {1} -f 128 --save-dyn -k CPDS --norm blablabla -o {2}".format( - self.lcA, - self.lcB, - os.path.join(self.datadir, "monol_test_3-50keV_wrong"), - ) + out = os.path.join(self.datadir, "monol_test_3-50keV_wrong") + command = f"{self.lcA} {self.lcB} -f 128 --save-dyn -k CPDS --norm blablabla -o {out}" with pytest.warns(UserWarning, match="Beware! Unknown normalization"): hen.fspec.main(command.split()) def test_cpds_dtbig(self): """Test CPDS production.""" - command = "{0} {1} -f 128 --save-dyn -k CPDS --save-all --norm " "frac -o {2}".format( - self.lcA, - self.lcB, - os.path.join(self.datadir, "monol_test_3-50keV_dtb"), - ) + out = os.path.join(self.datadir, "monol_test_3-50keV_dtb") + command = f"{self.lcA} {self.lcB} -f 128 --save-dyn -k CPDS --save-all --norm frac -o {out}" command += " -b 1" hen.fspec.main(command.split()) @@ -414,9 +404,10 @@ def test_dumpdyncpds(self): def test_rebinpds(self): """Test PDS rebinning 1.""" - command = "{0} -r 2".format( + data = ( os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds") + HEN_FILE_EXTENSION ) + command = f"{data} -r 2" hen.rebin.main(command.split()) os.path.exists( os.path.join( @@ -427,10 +418,11 @@ def test_rebinpds(self): def test_rebinpds_geom(self): """Test geometrical PDS rebinning.""" - command = "{0} {1} -r 1.03".format( + data_a, data_b = ( os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds") + HEN_FILE_EXTENSION, os.path.join(self.datadir, "monol_testB_nustar_fpmb_3-50keV_pds") + HEN_FILE_EXTENSION, ) + command = f"{data_a} {data_b} -r 1.03" hen.rebin.main(command.split()) os.path.exists( os.path.join( @@ -447,9 +439,8 @@ def test_rebinpds_geom(self): def test_rebincpds(self): """Test CPDS rebinning.""" - command = "{0} -r 2".format( - os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") + HEN_FILE_EXTENSION - ) + data = os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") + HEN_FILE_EXTENSION + command = f"{data} -r 2" hen.rebin.main(command.split()) os.path.exists( os.path.join( @@ -460,9 +451,8 @@ def test_rebincpds(self): def test_rebincpds_geom(self): """Test CPDS geometrical rebinning.""" - command = "{0} -r 1.03".format( - os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") + HEN_FILE_EXTENSION - ) + data = os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") + HEN_FILE_EXTENSION + command = f"{data} -r 1.03" hen.rebin.main(command.split()) os.path.exists( os.path.join( @@ -579,19 +569,22 @@ def test_fit_pds_f_no_of_intervals_invalid(self): def test_savexspec(self): """Test save as Xspec 1.""" - command = "{0}".format( + data = ( os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds_rebin2") + HEN_FILE_EXTENSION ) + command = f"{data}" hen.save_as_xspec.main(command.split()) os.path.exists(os.path.join(self.datadir, "monol_testA_nustar_fpmb_3-50keV_pds_rebin2.pha")) def test_savexspec_geom(self): """Test save as Xspec 2.""" - command = "{0}".format( + data = ( os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds_rebin1.03") + HEN_FILE_EXTENSION ) + + command = f"{data}" hen.save_as_xspec.main(command.split()) os.path.exists( diff --git a/hendrics/tests/test_gti.py b/hendrics/tests/test_gti.py index 11d72f77..b3f635ba 100644 --- a/hendrics/tests/test_gti.py +++ b/hendrics/tests/test_gti.py @@ -49,14 +49,13 @@ def setup_class(cls): "monol_testB_nustar_fpmb_ev_calib" + HEN_FILE_EXTENSION, ) cls.par = _dummy_par("bubububu.par") - command = "{0} {1}".format( + data_a, data_b = ( os.path.join(cls.datadir, "monol_testA.evt"), os.path.join(cls.datadir, "monol_testB.evt"), ) + command = f"{data_a} {data_b}" hen.read_events.main(command.split()) - command = "{} {} -r {}".format( - cls.ev_fileA, cls.ev_fileB, os.path.join(cls.datadir, "test.rmf") - ) + command = f"{cls.ev_fileA} {cls.ev_fileB} -r {os.path.join(cls.datadir, 'test.rmf')}" hen.calibrate.main(command.split()) cls.lcA = os.path.join(os.path.join(cls.datadir, "monol_testA_lc" + HEN_FILE_EXTENSION)) cls.lcB = os.path.join(os.path.join(cls.datadir, "monol_testB_lc" + HEN_FILE_EXTENSION)) diff --git a/hendrics/tests/test_lc.py b/hendrics/tests/test_lc.py index e686c449..b35bedb4 100644 --- a/hendrics/tests/test_lc.py +++ b/hendrics/tests/test_lc.py @@ -56,9 +56,8 @@ def test_treat_event_file_nustar(self): assert data.mjdref > 0 def test_treat_event_file_nustar_energy(self): - command = "{0} -r {1} --nproc 2".format( - self.new_filename, os.path.join(self.datadir, "test.rmf") - ) + rmf = os.path.join(self.datadir, "test.rmf") + command = f"{self.new_filename} -r {rmf} --nproc 2" hen.calibrate.main(command.split()) lcurve_from_events(self.calib_filename, e_interval=[3, 50]) @@ -106,16 +105,18 @@ def setup_class(cls): "monol_testB_nustar_fpmb_ev_calib" + HEN_FILE_EXTENSION, ) cls.par = _dummy_par("bubububu.par") - command = "{0} {1} --discard-calibration".format( + data_a, data_b = ( os.path.join(cls.datadir, "monol_testA.evt"), os.path.join(cls.datadir, "monol_testB.evt"), ) + command = f"{data_a} {data_b} --discard-calibration" hen.read_events.main(command.split()) - command = "{} {} -r {}".format( + data_a, data_b, rmf = ( os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "test.rmf"), ) + command = f"{data_a} {data_b} -r {rmf}" hen.calibrate.main(command.split()) def test_lcurve(self): @@ -141,14 +142,8 @@ def test_lcurve(self): assert np.allclose(gti_to_test, lc.gti) def test_lcurve_B(self): - command = ("{0} -e {1} {2} --safe-interval " "{3} {4} -b 0.5 -o {5}").format( - self.ev_fileBcal, - 3, - 50, - 100, - 300, - os.path.join(self.datadir, "monol_testB_E3-50_lc" + HEN_FILE_EXTENSION), - ) + out = os.path.join(self.datadir, "monol_testB_E3-50_lc" + HEN_FILE_EXTENSION) + command = f"{self.ev_fileBcal} -e 3 50 --safe-interval 100 300 -b 0.5 -o {out}" hen.lcurve.main(command.split()) assert os.path.exists( os.path.join(self.datadir, "monol_testB_E3-50_lc" + HEN_FILE_EXTENSION) @@ -209,9 +204,9 @@ def test_fits_lcurve0(self): lcurve_ftools = os.path.join(self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION) - command = "{0} --outfile {1}".format( - self.ev_fileAcal, os.path.join(self.datadir, "lcurve_lc") - ) + out = os.path.join(self.datadir, "lcurve_lc") + command = f"{self.ev_fileAcal} --outfile {out}" + hen.lcurve.main(command.split()) assert os.path.exists(os.path.join(self.datadir, "lcurve_lc") + HEN_FILE_EXTENSION) @@ -330,36 +325,29 @@ def testbaselinelc_nooutroot(self): def test_lcurve_error_uncalibrated(self): """Test light curve error from uncalibrated file.""" - command = ("{0} -e {1} {2}").format( - os.path.join( - self.datadir, - "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION, - ), - 3, - 50, + data = os.path.join( + self.datadir, + "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION, ) + command = f"{data} -e 3 50" with pytest.raises(ValueError, match="Did you run HENcalibrate?"): hen.lcurve.main(command.split()) def test_lcurve_pi_filtering(self): """Test light curve using PI filtering.""" - command = ("{0} --pi-interval {1} {2}").format( - os.path.join( - self.datadir, - "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION, - ), - 10, - 300, + data = os.path.join( + self.datadir, + "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION, ) + command = f"{data} --pi-interval {10} {300}" hen.lcurve.main(command.split()) def test_rebinlc(self): """Test LC rebinning.""" - command = "{0} -r 4".format( - os.path.join(self.datadir, "monol_testA_E3-50_lc") + HEN_FILE_EXTENSION - ) + data = os.path.join(self.datadir, "monol_testA_E3-50_lc") + HEN_FILE_EXTENSION + command = f"{data} -r 4" hen.rebin.main(command.split()) def test_save_fvar_from_lc(self): From 167332cef2fe4bcd9448f330882b4f13aaeba2ac Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 21:28:10 +0200 Subject: [PATCH 33/58] Fix some import errors --- hendrics/tests/test_efsearch.py | 8 ++------ hendrics/tests/test_fspec.py | 2 +- hendrics/varenergy.py | 23 ++++++++--------------- 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/hendrics/tests/test_efsearch.py b/hendrics/tests/test_efsearch.py index 219c9b9c..4618e264 100644 --- a/hendrics/tests/test_efsearch.py +++ b/hendrics/tests/test_efsearch.py @@ -1,4 +1,5 @@ import copy +import importlib import os from collections.abc import Iterable @@ -36,12 +37,7 @@ from . import cleanup_test_dir -try: - import pandas as pd - - HAS_PD = True -except ImportError: - HAS_PD = False +HAS_PD = importlib.util.find_spec("pandas") is not None class TestEFsearch: diff --git a/hendrics/tests/test_fspec.py b/hendrics/tests/test_fspec.py index 003c7cf1..967f1175 100644 --- a/hendrics/tests/test_fspec.py +++ b/hendrics/tests/test_fspec.py @@ -4,7 +4,7 @@ import numpy as np try: - from numpy import exceptions + import numpy.exceptions from numpy.exceptions import ComplexWarning except ImportError: from numpy import ComplexWarning diff --git a/hendrics/varenergy.py b/hendrics/varenergy.py index daad14b2..559db160 100644 --- a/hendrics/varenergy.py +++ b/hendrics/varenergy.py @@ -5,24 +5,17 @@ import warnings import numpy as np +from stingray.varenergyspectrum import ( + CountSpectrum, + CovarianceSpectrum, + LagSpectrum, + RmsSpectrum, +) +from stingray.varenergyspectrum import VarEnergySpectrum as StingrayVes from astropy import log from astropy.table import Table -try: - from stingray.varenergyspectrum import ( - CountSpectrum, - CovarianceSpectrum, - LagSpectrum, - RmsSpectrum, - _decode_energy_specification, - ) - from stingray.varenergyspectrum import VarEnergySpectrum as VES -except ImportError: - VES = object - warnings.warn("Please update stingray to the latest version.") - - from .base import hen_root, interpret_bintime from .io import load_events @@ -102,7 +95,7 @@ def varenergy_from_astropy_table(fname): return varenergy -class VarEnergySpectrum(VES): +class VarEnergySpectrum(StingrayVes): def __init__(self): for attr in [ "ref_band", From 3c9aa4634d916c2d446bca95dfe6bf3d75f5901c Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 21:37:33 +0200 Subject: [PATCH 34/58] use pathlib when possible --- hendrics/tests/__init__.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hendrics/tests/__init__.py b/hendrics/tests/__init__.py index 90e741cb..793c96ba 100644 --- a/hendrics/tests/__init__.py +++ b/hendrics/tests/__init__.py @@ -1,6 +1,7 @@ import glob import os import shutil +from pathlib import Path def _dummy_par(par, pb=1e20, a1=0.0, f0=1.0): @@ -52,12 +53,13 @@ def cleanup_test_dir(datadir): file_list.extend(find_file_pattern_in_dir(pattern, datadir)) for f in file_list: - if os.path.exists(f) and not os.path.isdir(f): + f = Path(f) + if f.exists() and not f.is_dir(): print("Removing " + f) - os.remove(f) - elif os.path.exists(f) and os.path.isdir(f): + f.unlink() + elif f.exists() and f.is_dir(): print("Removing directory " + f) - shutil.rmtree(f) + shutil.rmtree(str(f)) patterns = ["*_pds*/", "*_cpds*/", "*_sum/"] @@ -65,5 +67,5 @@ def cleanup_test_dir(datadir): for pattern in patterns: dir_list.extend(find_file_pattern_in_dir(pattern, datadir)) for f in dir_list: - if os.path.exists(f): + if Path(f).exists(): shutil.rmtree(f) From 8b6e2d568fd161eb36dafbb9affe6de9518ea38f Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 22:11:46 +0200 Subject: [PATCH 35/58] More syntax fixes --- hendrics/io.py | 9 +++++---- hendrics/lcurve.py | 9 +++------ hendrics/phasetag.py | 5 +---- hendrics/tests/__init__.py | 2 +- pyproject.toml | 10 ++++++++++ 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/hendrics/io.py b/hendrics/io.py index 25da421e..84d005d6 100644 --- a/hendrics/io.py +++ b/hendrics/io.py @@ -1,6 +1,8 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """Functions to perform input/output operations.""" +from __future__ import annotations + import copy import glob import importlib @@ -12,7 +14,6 @@ import sys import warnings from collections.abc import Iterable -from typing import Tuple import numpy as np from stingray.base import StingrayObject, StingrayTimeseries @@ -163,7 +164,7 @@ def get_energy_from_events(ev): return elabel, energy -def filter_energy(ev: EventList, emin: float, emax: float) -> Tuple[EventList, str]: +def filter_energy(ev: EventList, emin: float, emax: float) -> tuple[EventList, str]: """Filter event list by energy (or PI) If an ``energy`` attribute is present, uses it. Otherwise, it switches @@ -485,7 +486,7 @@ def get_file_type(fname, raw_data=False): if isinstance(contents_raw, Table): ftype_raw = recognize_stingray_table(contents_raw) if raw_data: - contents = dict([(col, contents_raw[col]) for col in contents_raw.colnames]) + contents = {col: contents_raw[col] for col in contents_raw.colnames} contents.update(contents_raw.meta) elif "__sr__class__type__" in contents_raw: ftype_raw = contents_raw["__sr__class__type__"] @@ -1248,7 +1249,7 @@ def main(args=None): print("-" * len(fname)) print(f"{fname}") print("-" * len(fname)) - if fname.endswith(".fits") or fname.endswith(".evt"): + if fname.endswith((".fits", ".evt")): print("This FITS file contains:", end="\n\n") print_fits_info(fname) print("-" * len(fname)) diff --git a/hendrics/lcurve.py b/hendrics/lcurve.py index e14c99e5..06b66d7f 100644 --- a/hendrics/lcurve.py +++ b/hendrics/lcurve.py @@ -542,8 +542,7 @@ def lcurve_from_fits( """WARNING! FITS light curve handling is still under testing. Absolute times might be incorrect.""" ) - # TODO: - # treat consistently TDB, UTC, TAI, etc. This requires some documentation + # TODO: treat consistently TDB, UTC, TAI, etc. This requires some documentation # reading. For now, we assume TDB import numpy as np from stingray.gti import create_gti_from_condition @@ -602,8 +601,7 @@ def lcurve_from_fits( # for lcurve light curves this should instead work if tunit == "d": - # TODO: - # Check this. For now, I assume TD (JD - 2440000.5). + # TODO: Check this. For now, I assume TD (JD - 2440000.5). # This is likely wrong timezero = Time(2440000.5 + timezero, scale="tdb", format="jd") tstart = Time(2440000.5 + tstart, scale="tdb", format="jd") @@ -857,8 +855,7 @@ def _execute_lcurve(args): outfiles.append(wrap_fun(a)) else: pool = Pool(processes=args.nproc) - for i in pool.imap_unordered(wrap_fun, arglist): - outfiles.append(i) + outfiles = list(pool.imap_unordered(wrap_fun, arglist)) pool.close() log.debug(f"{outfiles}") diff --git a/hendrics/phasetag.py b/hendrics/phasetag.py index e2e22daf..66e3d133 100644 --- a/hendrics/phasetag.py +++ b/hendrics/phasetag.py @@ -273,10 +273,7 @@ def phase_tag_fits( cols = table.columns # create new list of columns, copying all columns from other table - newlist = [] - - for c in cols: - newlist.append(c) + newlist = list(cols) if create: # then, create new column with orbital demodulation diff --git a/hendrics/tests/__init__.py b/hendrics/tests/__init__.py index 793c96ba..523867c4 100644 --- a/hendrics/tests/__init__.py +++ b/hendrics/tests/__init__.py @@ -25,7 +25,7 @@ def _dummy_par(par, pb=1e20, a1=0.0, f0=1.0): def find_file_pattern_in_dir(pattern, directory): - return glob.glob(os.path.join(directory, pattern)) + return Path(directory).glob(pattern) def cleanup_test_dir(datadir): diff --git a/pyproject.toml b/pyproject.toml index 6db51fd9..bf7a813e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -314,6 +314,16 @@ lint.ignore = [ # NOTE: non-permanent exclusions should be added to `.ruff.toml # flake8-use-pathlib (PTH) "PTH123", # builtin-open (not worth creating a Path object, builtin open is fine) + "PTH118", # os.path.join is fine + "PTH207", # standard glob is fine + "PTH120", # os.path.dirname is fine + "PTH110", # os.path.exists is fine + "PTH100", # os.path.abspath is fine + "PTH122", # os.path.splitext is fine + "PTH119", # os.path.basename is fine + "PTH109", # os.getcwd is fine + "PTH108", # os.unlink is fine + "PTH103", # os.makedirs is fine # flake8-simplify (SIM) "SIM103", # needless-bool (cannot be safely applied in all contexts (np.True_ is not True)) From 876021204821849a2e21e593a1ce3d3e492b3bdb Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 22:31:54 +0200 Subject: [PATCH 36/58] More syntax fixes --- hendrics/base.py | 4 +--- hendrics/conftest.py | 4 ++-- hendrics/create_gti.py | 8 +++++--- hendrics/efsearch.py | 4 ++-- hendrics/fspec.py | 18 +++++++++++------- hendrics/io.py | 6 +----- hendrics/plot.py | 4 ++-- hendrics/power_colors.py | 12 +++++++----- hendrics/read_events.py | 8 ++++---- hendrics/rebin.py | 10 ++++++---- hendrics/tests/test_fake.py | 4 ++-- hendrics/tests/test_io.py | 2 +- 12 files changed, 44 insertions(+), 40 deletions(-) diff --git a/hendrics/base.py b/hendrics/base.py index d0956613..f70c2fab 100644 --- a/hendrics/base.py +++ b/hendrics/base.py @@ -30,8 +30,6 @@ from astropy.table import Table try: - import pint - import pint.toa as toa from pint.models import get_model HAS_PINT = True @@ -269,7 +267,7 @@ def _order_list_of_arrays(data, order): >>> assert _order_list_of_arrays(2, order) is None """ if hasattr(data, "items"): - data = dict((i[0], np.asarray(i[1])[order]) for i in data.items()) + data = {i[0]: np.asarray(i[1])[order] for i in data.items()} elif hasattr(data, "index"): data = [np.asarray(i)[order] for i in data] else: diff --git a/hendrics/conftest.py b/hendrics/conftest.py index 684a6ab3..357f4971 100644 --- a/hendrics/conftest.py +++ b/hendrics/conftest.py @@ -17,11 +17,11 @@ try: - import matplotlib + import matplotlib as mpl except ImportError: pass else: - matplotlib.use("Agg") + mpl.use("Agg") def pytest_configure(config): diff --git a/hendrics/create_gti.py b/hendrics/create_gti.py index 11db3025..8c0ed159 100644 --- a/hendrics/create_gti.py +++ b/hendrics/create_gti.py @@ -132,9 +132,11 @@ def main(args=None): "--filter", type=str, default=None, - help="Filter expression, that has to be a valid " - + "Python boolean operation on a data variable " - + "contained in the files", + help=( + "Filter expression, that has to be a valid " + "Python boolean operation on a data variable " + "contained in the files" + ), ) parser.add_argument( diff --git a/hendrics/efsearch.py b/hendrics/efsearch.py index 8ad2d595..cd36521b 100644 --- a/hendrics/efsearch.py +++ b/hendrics/efsearch.py @@ -614,10 +614,10 @@ def transient_search( def plot_transient_search(results, gif_name=None): - import matplotlib + import matplotlib as mpl import matplotlib.pyplot as plt - matplotlib.use("Agg") + mpl.use("Agg") if gif_name is None: gif_name = "transients.gif" diff --git a/hendrics/fspec.py b/hendrics/fspec.py index 541dc1c6..b4b0385b 100644 --- a/hendrics/fspec.py +++ b/hendrics/fspec.py @@ -720,10 +720,12 @@ def main(args=None): "--bintime", type=float, default=1 / 4096, - help="Light curve bin time; if negative, interpreted" - + " as negative power of 2." - + " Default: 2^-10, or keep input lc bin time" - + " (whatever is larger)", + help=( + "Light curve bin time; if negative, interpreted" + " as negative power of 2." + " Default: 2^-10, or keep input lc bin time" + " (whatever is larger)" + ), ) parser.add_argument( "-r", @@ -744,9 +746,11 @@ def main(args=None): "--kind", type=str, default="PDS,CPDS,cos", - help="Spectra to calculate, as comma-separated list" - + " (Accepted: PDS and CPDS;" - + ' Default: "PDS,CPDS")', + help=( + "Spectra to calculate, as comma-separated list" + " (Accepted: PDS and CPDS;" + ' Default: "PDS,CPDS")' + ), ) parser.add_argument( "--norm", diff --git a/hendrics/io.py b/hendrics/io.py index 84d005d6..a9d91b15 100644 --- a/hendrics/io.py +++ b/hendrics/io.py @@ -21,12 +21,8 @@ from astropy.table import Table from hendrics.base import get_file_format, splitext_improved -try: - import h5py +HAS_H5PY = importlib.util.find_spec("h5py") is not None - HAS_H5PY = True -except ImportError: - HAS_H5PY = False try: import netCDF4 as nc diff --git a/hendrics/plot.py b/hendrics/plot.py index 68e6078d..5ff5bad5 100644 --- a/hendrics/plot.py +++ b/hendrics/plot.py @@ -905,9 +905,9 @@ def main(args=None): args = parser.parse_args(args) if args.noplot and args.figname is None: args.figname = args.files[0].replace(HEN_FILE_EXTENSION, ".png") - import matplotlib + import matplotlib as mpl - matplotlib.use("Agg") + mpl.use("Agg") if args.xlin: args.xlog = False if args.ylin: diff --git a/hendrics/power_colors.py b/hendrics/power_colors.py index 8a6a3e7a..8cd3a441 100644 --- a/hendrics/power_colors.py +++ b/hendrics/power_colors.py @@ -155,10 +155,12 @@ def main(args=None): "--bintime", type=float, default=1 / 64, - help="Light curve bin time; if negative, interpreted" - + " as negative power of 2." - + " Default: 2^-10, or keep input lc bin time" - + " (whatever is larger)", + help=( + "Light curve bin time; if negative, interpreted" + " as negative power of 2." + " Default: 2^-10, or keep input lc bin time" + " (whatever is larger)" + ), ) parser.add_argument( "--cross", @@ -177,7 +179,7 @@ def main(args=None): files = args.files if args.cross: - files = [frange for frange in zip(files[::2], files[1::2])] + files = list(zip(files[::2], files[1::2])) outfiles = [] with log.log_to_file("HENcolors.log"): diff --git a/hendrics/read_events.py b/hendrics/read_events.py index 64c094f3..c4309aaa 100644 --- a/hendrics/read_events.py +++ b/hendrics/read_events.py @@ -278,7 +278,7 @@ def join_eventlists(event_file1, event_file2, new_event_file=None, ignore_instr= events2 = load_events(event_file2) if ignore_instr: - events1.instr = events2.instr = ",".join((events1.instr, events2.instr)) + events1.instr = events2.instr = f"{events1.instr},{events2.instr}" if events2.time.size == 0 or events2.gti.size == 0: warnings.warn(f"{event_file2} has no good events") @@ -410,18 +410,18 @@ def split_eventlist(fname, max_length, overlap=None): event_times = ev.time GTI = ev.gti t0 = GTI[0, 0] - count = 0 + from .base import nchars_in_int_value nchars = nchars_in_int_value((GTI.max() - t0) / max_length) all_files = [] - for new_ev in _split_events(ev, max_length, overlap): + for count, new_ev in enumerate(_split_events(ev, max_length, overlap)): newfname = root + f"_{count:0{nchars}d}" + HEN_FILE_EXTENSION save_events(new_ev, newfname) all_files.append(newfname) - count += 1 + return all_files diff --git a/hendrics/rebin.py b/hendrics/rebin.py index 0dc647d8..2c0ae727 100644 --- a/hendrics/rebin.py +++ b/hendrics/rebin.py @@ -46,10 +46,12 @@ def main(args=None): "--rebin", type=float, default=1, - help="Rebinning to apply. Only if the quantity to" - + " rebin is a (C)PDS, it is possible to specify a" - + " non-integer rebin factor, in which case it is" - + " interpreted as a geometrical binning factor", + help=( + "Rebinning to apply. Only if the quantity to" + " rebin is a (C)PDS, it is possible to specify a" + " non-integer rebin factor, in which case it is" + " interpreted as a geometrical binning factor" + ), ) _add_default_args(parser, ["loglevel", "debug"]) diff --git a/hendrics/tests/test_fake.py b/hendrics/tests/test_fake.py index a9584d7e..e33ffa17 100644 --- a/hendrics/tests/test_fake.py +++ b/hendrics/tests/test_fake.py @@ -121,8 +121,8 @@ def test_deadtime_conversion(): original_rate = np.arange(1, 1000, 10) deadtime = 2.5e-3 rdet = hen.base.r_det(deadtime, original_rate) - rin = hen.base.r_in(deadtime, rdet) - np.testing.assert_almost_equal(rin, original_rate) + inner_radius = hen.base.r_in(deadtime, rdet) + np.testing.assert_almost_equal(inner_radius, original_rate) def verify_all_checksums(filename): diff --git a/hendrics/tests/test_io.py b/hendrics/tests/test_io.py index 577a16df..e2e1a163 100644 --- a/hendrics/tests/test_io.py +++ b/hendrics/tests/test_io.py @@ -628,7 +628,7 @@ def test_load_model_input_invalid_file_format(self): def test_load_data_fails(self): with pytest.raises(TypeError, match="The file type is not recognized"): - load_data("afile.fits") + load_data("a_file.fits") @classmethod def teardown_class(cls): From dae2f9854ada4933f9255d2fc997a3b9727b2224 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 22:32:10 +0200 Subject: [PATCH 37/58] Tolerate some more stuff --- pyproject.toml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index bf7a813e..9cc1d8c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -261,7 +261,11 @@ lint.select = ["ALL"] line-length = 100 exclude=[ "notebooks/*.ipynb", - "*.svg" + "*.svg", + "docs/conf.py", + "_astropy_init.py", + "__init__.py", + "compatibility.py", ] lint.ignore = [ # NOTE: non-permanent exclusions should be added to `.ruff.toml` instead. @@ -308,6 +312,8 @@ lint.ignore = [ # NOTE: non-permanent exclusions should be added to `.ruff.toml # pandas-vet (PD) "PD", + "PGH004", # noqa + # pylint (PLR and PLW) "PLR1730", # if-stmt-min-max (not always clearer, and sometimes slower) "PLW0642", # self-or-cls-assignment (occasionally desirable, very rarely a mistake) @@ -396,6 +402,8 @@ skip = """ ignore-words-list = """ aas, ans, + bu, + bubu, clen, coo, datas, From 37ef63c0f7b306af4a2268e7c1da4945855f6bae Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 21 Oct 2024 22:41:10 +0200 Subject: [PATCH 38/58] Last fixes to make codestyle pass --- hendrics/efsearch.py | 4 +++- hendrics/exvar.py | 1 - hendrics/fold.py | 18 +++++++++--------- hendrics/io.py | 26 ++++++++++++-------------- hendrics/phasetag.py | 4 +--- hendrics/plot.py | 2 +- 6 files changed, 26 insertions(+), 29 deletions(-) diff --git a/hendrics/efsearch.py b/hendrics/efsearch.py index cd36521b..d2cb8512 100644 --- a/hendrics/efsearch.py +++ b/hendrics/efsearch.py @@ -1,6 +1,8 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """Search for pulsars.""" +from __future__ import annotations + import argparse import copy import os @@ -781,7 +783,7 @@ def search_with_qffa_step( oversample=8, n=1, search_fdot=True, -): +) -> tuple[np.array, np.array, np.array]: """Single step of quasi-fast folding algorithm.""" # Cast to standard double, or Numba's histogram2d will fail # horribly. diff --git a/hendrics/exvar.py b/hendrics/exvar.py index cd582ac4..148a3368 100644 --- a/hendrics/exvar.py +++ b/hendrics/exvar.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 """ Created on Thu Aug 17 08:55:47 2017 diff --git a/hendrics/fold.py b/hendrics/fold.py index e01f0f91..f8af1209 100644 --- a/hendrics/fold.py +++ b/hendrics/fold.py @@ -334,15 +334,15 @@ def get_TOAs_from_events(events, folding_length, *frequency_derivatives, **kwarg toa_err : array-like errorbars on TOAs, in the same units as TOAs. """ - template = kwargs["template"] if "template" in kwargs else None - mjdref = kwargs["mjdref"] if "mjdref" in kwargs else None - nbin = kwargs["nbin"] if "nbin" in kwargs else 16 - pepoch = kwargs["pepoch"] if "pepoch" in kwargs else None - timfile = kwargs["timfile"] if "timfile" in kwargs else "out.tim" - gti = kwargs["gti"] if "gti" in kwargs else None - label = kwargs["label"] if "label" in kwargs else None - quick = kwargs["quick"] if "quick" in kwargs else False - ephem = kwargs["ephem"] if "ephem" in kwargs else "DE421" + template = kwargs.get("template") + mjdref = kwargs.get("mjdref") + nbin = kwargs.get("nbin", 16) + pepoch = kwargs.get("pepoch") + timfile = kwargs.get("timfile", "out.tim") + gti = kwargs.get("gti") + label = kwargs.get("label") + quick = kwargs.get("quick", False) + ephem = kwargs.get("ephem", "DE421") pepoch = assign_value_if_none(pepoch, events[0]) gti = np.asarray(assign_value_if_none(gti, [[events[0], events[-1]]])) diff --git a/hendrics/io.py b/hendrics/io.py index a9d91b15..32ef7ab2 100644 --- a/hendrics/io.py +++ b/hendrics/io.py @@ -17,12 +17,21 @@ import numpy as np from stingray.base import StingrayObject, StingrayTimeseries +from stingray.crossspectrum import AveragedCrossspectrum, Crossspectrum +from stingray.events import EventList +from stingray.lightcurve import Lightcurve +from stingray.powerspectrum import AveragedPowerspectrum, Powerspectrum +from stingray.pulse.modeling import SincSquareModel +from stingray.pulse.search import search_best_peaks +from stingray.utils import assign_value_if_none +from astropy import log +from astropy.logger import AstropyUserWarning +from astropy.modeling.core import Model from astropy.table import Table from hendrics.base import get_file_format, splitext_improved -HAS_H5PY = importlib.util.find_spec("h5py") is not None - +from .base import find_peaks_in_image, hen_root, is_string try: import netCDF4 as nc @@ -34,19 +43,8 @@ warnings.warn(msg) HEN_FILE_EXTENSION = ".p" HAS_NETCDF = False -from stingray.crossspectrum import AveragedCrossspectrum, Crossspectrum -from stingray.events import EventList -from stingray.lightcurve import Lightcurve -from stingray.powerspectrum import AveragedPowerspectrum, Powerspectrum -from stingray.pulse.modeling import SincSquareModel -from stingray.pulse.search import search_best_peaks -from stingray.utils import assign_value_if_none -from astropy import log -from astropy.logger import AstropyUserWarning -from astropy.modeling.core import Model - -from .base import find_peaks_in_image, hen_root, is_string +HAS_H5PY = importlib.util.find_spec("h5py") is not None try: _ = np.complex256 diff --git a/hendrics/phasetag.py b/hendrics/phasetag.py index 66e3d133..e0c51c50 100644 --- a/hendrics/phasetag.py +++ b/hendrics/phasetag.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - import argparse import warnings @@ -120,7 +118,7 @@ def phase_tag( profile = raw_profile / exposure profile_err = np.sqrt(raw_profile) / exposure - sinpars, bu, bu = fit_profile(profile, profile_err, nperiods=2, baseline=True, debug=test) + sinpars, _, _ = fit_profile(profile, profile_err, nperiods=2, baseline=True, debug=test) fine_phases = np.linspace(0, 2, 1000 * 2) fitted_profile = std_fold_fit_func(sinpars, fine_phases) maxp = np.argmax(fitted_profile) diff --git a/hendrics/plot.py b/hendrics/plot.py index 5ff5bad5..f8f41e57 100644 --- a/hendrics/plot.py +++ b/hendrics/plot.py @@ -280,7 +280,7 @@ def plot_pds( level = lev # Can be modified below y = pds[1:] - yerr = yerr = None if epds is None else epds[1:] + yerr = None if epds is None else epds[1:] if not white_sub: white_sub = norm.lower() in ["rms", "frac"] and xlog and ylog From d8340f606e3b14f69ca6487f06b9c8d53a3e1256 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 10:23:13 +0200 Subject: [PATCH 39/58] Make docs build work; fix bad imports --- docs/conf.py | 53 ++-- docs/scripts/cli.rst | 658 ++++++++++++++++++------------------------ hendrics/base.py | 58 ++-- hendrics/ffa.py | 5 +- hendrics/io.py | 2 +- hendrics/ml_timing.py | 2 +- pyproject.toml | 40 ++- 7 files changed, 390 insertions(+), 428 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index c6efc6d9..068f708f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -34,6 +34,12 @@ except ImportError: print("ERROR: the documentation requires the sphinx-astropy package to be installed") sys.exit(1) +try: + import tomllib +except ImportError: + # Help users on older alphas + import tomli as tomllib +from pathlib import Path # Get configuration information from setup.cfg from configparser import ConfigParser @@ -43,8 +49,9 @@ ON_RTD = os.environ.get("READTHEDOCS") == "True" ON_TRAVIS = os.environ.get("TRAVIS") == "true" -conf.read([os.path.join(os.path.dirname(__file__), "..", "setup.cfg")]) -setup_cfg = dict(conf.items("metadata")) +# Grab minversion from pyproject.toml +with (Path(__file__).parents[1] / "pyproject.toml").open("rb") as f: + pyproject = tomllib.load(f) # -- General configuration ---------------------------------------------------- @@ -70,16 +77,16 @@ # -- Project information ------------------------------------------------------ # This does not *have* to match the package name, but typically does -project = setup_cfg["name"] -author = setup_cfg["author"] -copyright = f"{datetime.datetime.now().year}, {setup_cfg['author']}" +project = pyproject["project"]["name"] +author = ",".join(pyproject["project"]["authors"][0]["name"]) +copyright = "{0}, {1}".format(datetime.datetime.now().year, pyproject["project"]["authors"]) # 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. -import_module(setup_cfg["name"]) -package = sys.modules[setup_cfg["name"]] +import_module(pyproject["project"]["name"]) +package = sys.modules[pyproject["project"]["name"]] # The short X.Y version. version = package.__version__.split("-", 1)[0] @@ -155,17 +162,22 @@ extensions += ["sphinx_toolbox.collapse"] # -- Options for the edit_on_github extension --------------------------------- -if setup_cfg.get("edit_on_github").lower() == "true": - extensions += ["sphinx_astropy.ext.edit_on_github"] +# Trust the links from these sites, even if they might have Client errors or other minor issues +linkcheck_ignore = [ + r"https://doi.org/", + r"https://arxiv.org/", + r"https://.*adsabs.harvard.edu/", + r"https://zenodo.org/", +] - edit_on_github_project = setup_cfg["github_project"] - edit_on_github_branch = "main" +# -- Options for the edit_on_github extension --------------------------------- - edit_on_github_source_root = "" - edit_on_github_doc_root = "docs" +edit_on_github_branch = "main" # -- Resolving issue number to links in changelog ----------------------------- -github_issues_url = f"https://github.com/{setup_cfg['github_project']}/issues/" +github_issues_url = "https://github.com/{0}/issues/".format( + pyproject["project"]["urls"]["repository"] +) # -- Turn on nitpicky mode for sphinx (to warn about references not found) ---- # @@ -194,11 +206,14 @@ # nitpick_ignore.append((dtype, six.u(target))) if not ON_RTD and not ON_TRAVIS: - scripts = dict(conf.items("options.entry_points"))["console_scripts"] - - scripts = dict( - [(l.strip() for l in line.split("=")) for line in scripts.split("\n") if line.strip() != ""] - ) + # scripts = dict(conf.items("options.entry_points"))["console_scripts"] + print(pyproject) + scripts = pyproject["project"]["scripts"] + print(scripts) + + # scripts = dict( + # [(l.strip() for l in line.split("=")) for line in scripts.split("\n") if line.strip() != ""] + # ) import subprocess as sp cli_file = os.path.join(os.getcwd(), "scripts", "cli.rst") diff --git a/docs/scripts/cli.rst b/docs/scripts/cli.rst index 62793b01..a7ebe1ae 100644 --- a/docs/scripts/cli.rst +++ b/docs/scripts/cli.rst @@ -6,11 +6,10 @@ HEN2xspec :: - usage: HEN2xspec [-h] [--flx2xsp] [--loglevel LOGLEVEL] [--debug] - files [files ...] + usage: HEN2xspec [-h] [--flx2xsp] [--loglevel LOGLEVEL] [--debug] files [files ...] - Save a frequency spectrum in a qdp file that can be read by flx2xsp and - produce a XSpec-compatible spectrumfile + Save a frequency spectrum in a qdp file that can be read by flx2xsp and produce a XSpec-compatible + spectrumfile positional arguments: files List of files @@ -18,8 +17,8 @@ HEN2xspec options: -h, --help show this help message and exit --flx2xsp Also call flx2xsp at the end - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -28,12 +27,10 @@ HENaccelsearch :: - usage: HENaccelsearch [-h] [--outfile OUTFILE] [--emin EMIN] [--emax EMAX] - [--fmin FMIN] [--fmax FMAX] [--nproc NPROC] - [--zmax ZMAX] [--delta-z DELTA_Z] [--interbin] - [--pad-to-double] [--detrend DETREND] - [--deorbit-par DEORBIT_PAR] [--red-noise-filter] - [--loglevel LOGLEVEL] [--debug] + usage: HENaccelsearch [-h] [--outfile OUTFILE] [--emin EMIN] [--emax EMAX] [--fmin FMIN] + [--fmax FMAX] [--nproc NPROC] [--zmax ZMAX] [--delta-z DELTA_Z] [--interbin] + [--pad-to-double] [--detrend DETREND] [--deorbit-par DEORBIT_PAR] + [--red-noise-filter] [--loglevel LOGLEVEL] [--debug] fname Run the accelerated search on pulsar data. @@ -57,8 +54,8 @@ HENaccelsearch --deorbit-par DEORBIT_PAR Parameter file in TEMPO2/PINT format --red-noise-filter Correct FFT for red noise (use with caution) - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -67,13 +64,11 @@ HENbaseline :: - usage: HENbaseline [-h] [-o OUT] [--loglevel LOGLEVEL] [--debug] - [-p ASYMMETRY] [-l LAM] + usage: HENbaseline [-h] [-o OUT] [--loglevel LOGLEVEL] [--debug] [-p ASYMMETRY] [-l LAM] files [files ...] - Subtract a baseline from the lightcurve using the Asymmetric Least Squares - algorithm. The two parameters p and lambda control the asymmetry and - smoothness of the baseline. See below for details. + Subtract a baseline from the lightcurve using the Asymmetric Least Squares algorithm. The two + parameters p and lambda control the asymmetry and smoothness of the baseline. See below for details. positional arguments: files List of files @@ -81,15 +76,14 @@ HENbaseline options: -h, --help show this help message and exit -o OUT, --out OUT Output file - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug use DEBUG logging level -p ASYMMETRY, --asymmetry ASYMMETRY - "asymmetry" parameter. Smaller values make the - baseline more "horizontal". Typically 0.001 < p < 0.1, - but not necessarily. - -l LAM, --lam LAM lambda, or "smoothness", parameter. Larger values make - the baseline stiffer. Typically 1e2 < lam < 1e9 + "asymmetry" parameter. Smaller values make the baseline more "horizontal". + Typically 0.001 < p < 0.1, but not necessarily. + -l LAM, --lam LAM lambda, or "smoothness", parameter. Larger values make the baseline stiffer. + Typically 1e2 < lam < 1e9 HENbinary @@ -97,9 +91,8 @@ HENbinary :: - usage: HENbinary [-h] [-l MAX_LENGTH] [-b BINTIME] - [-e ENERGY_INTERVAL ENERGY_INTERVAL] [-p DEORBIT_PAR] - [--nproc NPROC] [--loglevel LOGLEVEL] [--debug] + usage: HENbinary [-h] [-l MAX_LENGTH] [-b BINTIME] [-e ENERGY_INTERVAL ENERGY_INTERVAL] + [-p DEORBIT_PAR] [--nproc NPROC] [--loglevel LOGLEVEL] [--debug] files [files ...] Save light curves in a format readable to PRESTO @@ -116,11 +109,10 @@ HENbinary -e ENERGY_INTERVAL ENERGY_INTERVAL, --energy-interval ENERGY_INTERVAL ENERGY_INTERVAL Energy interval used for filtering -p DEORBIT_PAR, --deorbit-par DEORBIT_PAR - Deorbit data with this parameter file (requires PINT - installed) + Deorbit data with this parameter file (requires PINT installed) --nproc NPROC Number of processors to use - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -129,28 +121,24 @@ HENcalibrate :: - usage: HENcalibrate [-h] [-r RMF] [--rough] [-o] [--nproc NPROC] - [--loglevel LOGLEVEL] [--debug] + usage: HENcalibrate [-h] [-r RMF] [--rough] [-o] [--nproc NPROC] [--loglevel LOGLEVEL] [--debug] files [files ...] - Calibrate clean event files by associating the correct energy to each PI - channel. Uses either a specified rmf file or (for NuSTAR only) an rmf file - from the CALDB + Calibrate clean event files by associating the correct energy to each PI channel. Uses either a + specified rmf file or (for NuSTAR only) an rmf file from the CALDB positional arguments: files List of files options: -h, --help show this help message and exit - -r RMF, --rmf RMF rmf file used for calibration. Not working with XMM - data - --rough Rough calibration, without rmf file (only for NuSTAR, - XMM, and NICER). Only for compatibility purposes. This - is done automatically by HENreadevents + -r RMF, --rmf RMF rmf file used for calibration. Not working with XMM data + --rough Rough calibration, without rmf file (only for NuSTAR, XMM, and NICER). Only + for compatibility purposes. This is done automatically by HENreadevents -o, --overwrite Overwrite; default: no --nproc NPROC Number of processors to use - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -159,8 +147,8 @@ HENcolors :: - usage: HENcolors [-h] -e ENERGIES ENERGIES ENERGIES ENERGIES [-b BINTIME] - [--use-pi] [-o OUTFILE] [--loglevel LOGLEVEL] [--debug] + usage: HENcolors [-h] -e ENERGIES ENERGIES ENERGIES ENERGIES [-b BINTIME] [--use-pi] [-o OUTFILE] + [--loglevel LOGLEVEL] [--debug] files [files ...] Calculate color light curves @@ -171,17 +159,16 @@ HENcolors options: -h, --help show this help message and exit -e ENERGIES ENERGIES ENERGIES ENERGIES, --energies ENERGIES ENERGIES ENERGIES ENERGIES - The energy boundaries in keV used to calculate the - color. E.g. -e 2 3 4 6 means that the color will be - calculated as 4.-6./2.-3. keV. If --use-pi is + The energy boundaries in keV used to calculate the color. E.g. -e 2 3 4 6 + means that the color will be calculated as 4.-6./2.-3. keV. If --use-pi is specified, these are interpreted as PI channels -b BINTIME, --bintime BINTIME Bin time --use-pi Use the PI channel instead of energies -o OUTFILE, --outfile OUTFILE Output file - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -190,14 +177,11 @@ HENcreategti :: - usage: HENcreategti [-h] [-f FILTER] [-c] [--overwrite] [-a APPLY_GTI] - [-l MINIMUM_LENGTH] - [--safe-interval SAFE_INTERVAL SAFE_INTERVAL] - [--loglevel LOGLEVEL] [--debug] + usage: HENcreategti [-h] [-f FILTER] [-c] [--overwrite] [-a APPLY_GTI] [-l MINIMUM_LENGTH] + [--safe-interval SAFE_INTERVAL SAFE_INTERVAL] [--loglevel LOGLEVEL] [--debug] files [files ...] - Create GTI files from a filter expression, or applies previously created GTIs - to a file + Create GTI files from a filter expression, or applies previously created GTIs to a file positional arguments: files List of files @@ -205,21 +189,18 @@ HENcreategti options: -h, --help show this help message and exit -f FILTER, --filter FILTER - Filter expression, that has to be a valid Python - boolean operation on a data variable contained in the - files - -c, --create-only If specified, creates GTIs withouth applyingthem to - files (Default: False) + Filter expression, that has to be a valid Python boolean operation on a data + variable contained in the files + -c, --create-only If specified, creates GTIs without applyingthem to files (Default: False) --overwrite Overwrite original file (Default: False) -a APPLY_GTI, --apply-gti APPLY_GTI Apply a GTI from this file to input files -l MINIMUM_LENGTH, --minimum-length MINIMUM_LENGTH - Minimum length of GTIs (below this length, they will - be discarded) + Minimum length of GTIs (below this length, they will be discarded) --safe-interval SAFE_INTERVAL SAFE_INTERVAL Interval at start and stop of GTIs used for filtering - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -228,8 +209,7 @@ HENdeorbit :: - usage: HENdeorbit [-h] [-p DEORBIT_PAR] [--loglevel LOGLEVEL] [--debug] - files [files ...] + usage: HENdeorbit [-h] [-p DEORBIT_PAR] [--loglevel LOGLEVEL] [--debug] files [files ...] Deorbit the event arrival times @@ -239,10 +219,9 @@ HENdeorbit options: -h, --help show this help message and exit -p DEORBIT_PAR, --deorbit-par DEORBIT_PAR - Deorbit data with this parameter file (requires PINT - installed) - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + Deorbit data with this parameter file (requires PINT installed) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -253,8 +232,7 @@ HENdumpdyn usage: HENdumpdyn [-h] [--noplot] files [files ...] - Dump dynamical (cross) power spectra. This script is being reimplemented. - Please be patient :) + Dump dynamical (cross) power spectra. This script is being reimplemented. Please be patient :) positional arguments: files List of files in any valid HENDRICS format for PDS or CPDS @@ -269,17 +247,14 @@ HENefsearch :: - usage: HENefsearch [-h] -f FMIN -F FMAX [--emin EMIN] [--emax EMAX] - [--mean-fdot MEAN_FDOT] [--mean-fddot MEAN_FDDOT] - [--fdotmin FDOTMIN] [--fdotmax FDOTMAX] [--dynstep DYNSTEP] - [--npfact NPFACT] + usage: HENefsearch [-h] -f FMIN -F FMAX [--emin EMIN] [--emax EMAX] [--mean-fdot MEAN_FDOT] + [--mean-fddot MEAN_FDDOT] [--fdotmin FDOTMIN] [--fdotmax FDOTMAX] + [--dynstep DYNSTEP] [--npfact NPFACT] [--n-transient-intervals N_TRANSIENT_INTERVALS] [-n NBIN] - [--segment-size SEGMENT_SIZE] [--step STEP] - [--oversample OVERSAMPLE] [--fast] [--ffa] [--transient] - [--expocorr] [--find-candidates] [--conflevel CONFLEVEL] - [--fit-candidates] [--curve CURVE] - [--fit-frequency FIT_FREQUENCY] [-N N] [-p DEORBIT_PAR] - [--loglevel LOGLEVEL] [--debug] + [--segment-size SEGMENT_SIZE] [--step STEP] [--oversample OVERSAMPLE] [--fast] + [--ffa] [--transient] [--expocorr] [--find-candidates] [--conflevel CONFLEVEL] + [--fit-candidates] [--curve CURVE] [--fit-frequency FIT_FREQUENCY] [-N N] + [-p DEORBIT_PAR] [--loglevel LOGLEVEL] [--debug] files [files ...] Search for pulsars using the epoch folding or the Z_n^2 algorithm @@ -305,27 +280,23 @@ HENefsearch Number of transient intervals to investigate -n NBIN, --nbin NBIN Number of phase bins of the profile --segment-size SEGMENT_SIZE - Size of the event list segment to use (default None, - implying the whole observation) - --step STEP Step size of the frequency axis. Defaults to - 1/oversample/obs_length. + Size of the event list segment to use (default None, implying the whole + observation) + --step STEP Step size of the frequency axis. Defaults to 1/oversample/obs_length. --oversample OVERSAMPLE - Oversampling factor - frequency resolution improvement - w.r.t. the standard FFT's 1/obs_length. - --fast Use a faster folding algorithm. It automatically - searches for the first spin derivative using an - optimized step.This option ignores expocorr, + Oversampling factor - frequency resolution improvement w.r.t. the standard + FFT's 1/obs_length. + --fast Use a faster folding algorithm. It automatically searches for the first spin + derivative using an optimized step.This option ignores expocorr, fdotmin/max, segment-size, and step - --ffa Use *the* Fast Folding Algorithm by Staelin+69. No - accelerated search allowed at the moment. Only - recommended to search for slow pulsars. - --transient Look for transient emission (produces an animated GIF - with the dynamic Z search) - --expocorr Correct for the exposure of the profile bins. This - method is *much* slower, but it is useful for very - slow pulsars, where data gaps due to occultation or - SAA passages can significantly alter the exposure of - different profile bins. + --ffa Use *the* Fast Folding Algorithm by Staelin+69. No accelerated search + allowed at the moment. Only recommended to search for slow pulsars. + --transient Look for transient emission (produces an animated GIF with the dynamic Z + search) + --expocorr Correct for the exposure of the profile bins. This method is *much* slower, + but it is useful for very slow pulsars, where data gaps due to occultation + or SAA passages can significantly alter the exposure of different profile + bins. --find-candidates Find pulsation candidates using thresholding --conflevel CONFLEVEL percent confidence level for thresholding [0-100). @@ -333,13 +304,12 @@ HENefsearch --curve CURVE Kind of curve to use (sinc or Gaussian) --fit-frequency FIT_FREQUENCY Force the candidate frequency to FIT_FREQUENCY - -N N The number of harmonics to use in the search (the 'N' - in Z^2_N; only relevant to Z search!) + -N N The number of harmonics to use in the search (the 'N' in Z^2_N; only + relevant to Z search!) -p DEORBIT_PAR, --deorbit-par DEORBIT_PAR - Deorbit data with this parameter file (requires PINT - installed) - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + Deorbit data with this parameter file (requires PINT installed) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -348,8 +318,8 @@ HENexcvar :: - usage: HENexcvar [-h] [-c CHUNK_LENGTH] [--fraction-step FRACTION_STEP] - [--norm NORM] [--loglevel LOGLEVEL] [--debug] + usage: HENexcvar [-h] [-c CHUNK_LENGTH] [--fraction-step FRACTION_STEP] [--norm NORM] + [--loglevel LOGLEVEL] [--debug] files [files ...] Calculate excess variance in light curve chunks @@ -362,15 +332,13 @@ HENexcvar -c CHUNK_LENGTH, --chunk-length CHUNK_LENGTH Length in seconds of the light curve chunks --fraction-step FRACTION_STEP - If the step is not a full chunk_length but less,this - indicates the ratio between step step and - `chunk_length` - --norm NORM Choose between fvar, excvar and norm_excvar - normalization, referring to Fvar, excess variance, and - normalized excess variance respectively (see Vaughan - et al. 2003 for details). - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + If the step is not a full chunk_length but less,this indicates the ratio + between step step and `chunk_length` + --norm NORM Choose between fvar, excvar and norm_excvar normalization, referring to + Fvar, excess variance, and normalized excess variance respectively (see + Vaughan et al. 2003 for details). + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -379,8 +347,7 @@ HENexposure :: - usage: HENexposure [-h] [-o OUTROOT] [--plot] [--loglevel LOGLEVEL] [--debug] - lcfile uffile + usage: HENexposure [-h] [-o OUTROOT] [--plot] [--loglevel LOGLEVEL] [--debug] lcfile uffile Create exposure light curve based on unfiltered event files. @@ -393,8 +360,8 @@ HENexposure -o OUTROOT, --outroot OUTROOT Root of output file names --plot Plot on window - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -403,13 +370,12 @@ HENfake :: - usage: HENfake [-h] [-e EVENT_LIST] [-l LC] [-c CTRATE] [-o OUTNAME] - [-i INSTRUMENT] [-m MISSION] [--tstart TSTART] [--tstop TSTOP] - [--mjdref MJDREF] [--deadtime DEADTIME [DEADTIME ...]] - [--loglevel LOGLEVEL] [--debug] + usage: HENfake [-h] [-e EVENT_LIST] [-l LC] [-c CTRATE] [-o OUTNAME] [-i INSTRUMENT] [-m MISSION] + [--tstart TSTART] [--tstop TSTOP] [--mjdref MJDREF] + [--deadtime DEADTIME [DEADTIME ...]] [--loglevel LOGLEVEL] [--debug] - Create an event file in FITS format from an event list, or simulating it. If - input event list is not specified, generates the events randomly + Create an event file in FITS format from an event list, or simulating it. If input event list is not + specified, generates the events randomly options: -h, --help show this help message and exit @@ -428,11 +394,10 @@ HENfake --tstop TSTOP End time of the observation (s from MJDREF) --mjdref MJDREF Reference MJD --deadtime DEADTIME [DEADTIME ...] - Dead time magnitude. Can be specified as a single - number, or two. In this last case, the second value is - used as sigma of the dead time distribution - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + Dead time magnitude. Can be specified as a single number, or two. In this + last case, the second value is used as sigma of the dead time distribution + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -441,8 +406,7 @@ HENfiltevents :: - usage: HENfiltevents [-h] [--emin EMIN] [--emax EMAX] [--loglevel LOGLEVEL] - [--debug] [--test] + usage: HENfiltevents [-h] [--emin EMIN] [--emax EMAX] [--loglevel LOGLEVEL] [--debug] [--test] files [files ...] Filter events @@ -454,8 +418,8 @@ HENfiltevents -h, --help show this help message and exit --emin EMIN Minimum energy (or PI if uncalibrated) to plot --emax EMAX Maximum energy (or PI if uncalibrated) to plot - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level --test Only used for tests @@ -465,11 +429,10 @@ HENfold :: - usage: HENfold [-h] [-f FREQ] [--fdot FDOT] [--fddot FDDOT] [--tref TREF] - [-n NBIN] [--nebin NEBIN] [--emin EMIN] [--emax EMAX] - [--out-file-root OUT_FILE_ROOT] [--pepoch PEPOCH] [--norm NORM] - [--colormap COLORMAP] [-p DEORBIT_PAR] [--loglevel LOGLEVEL] - [--debug] [--test] + usage: HENfold [-h] [-f FREQ] [--fdot FDOT] [--fddot FDDOT] [--tref TREF] [-n NBIN] [--nebin NEBIN] + [--emin EMIN] [--emax EMAX] [--out-file-root OUT_FILE_ROOT] [--pepoch PEPOCH] + [--norm NORM] [--colormap COLORMAP] [-p DEORBIT_PAR] [--loglevel LOGLEVEL] [--debug] + [--test] file Plot a folded profile @@ -490,23 +453,18 @@ HENfold --out-file-root OUT_FILE_ROOT Root of the output files (plots and csv tables) --pepoch PEPOCH Reference epoch for timing parameters (MJD) - --norm NORM Normalization for the dynamical phase plot. Can be: - 'to1' (each profile normalized from 0 to 1); 'std' - (subtract the mean and divide by the standard - deviation); 'sub' (just subtract the mean of each - profile); 'ratios' (divide by the average profile, to - highlight changes). Prepending 'median' to any of - those options uses the median in place of the mean. - Appending '_smooth' smooths the 2d array with a - Gaussian filter. E.g. mediansub_smooth subtracts the - median and smooths the imagedefault None - --colormap COLORMAP Change the color map of the image. Any matplotlib - colormap is valid + --norm NORM Normalization for the dynamical phase plot. Can be: 'to1' (each profile + normalized from 0 to 1); 'std' (subtract the mean and divide by the standard + deviation); 'sub' (just subtract the mean of each profile); 'ratios' (divide + by the average profile, to highlight changes). Prepending 'median' to any of + those options uses the median in place of the mean. Appending '_smooth' + smooths the 2d array with a Gaussian filter. E.g. mediansub_smooth subtracts + the median and smooths the imagedefault None + --colormap COLORMAP Change the color map of the image. Any matplotlib colormap is valid -p DEORBIT_PAR, --deorbit-par DEORBIT_PAR - Deorbit data with this parameter file (requires PINT - installed) - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + Deorbit data with this parameter file (requires PINT installed) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level --test Only used for tests @@ -516,15 +474,13 @@ HENfspec :: - usage: HENfspec [-h] [-b BINTIME] [-r REBIN] [-f FFTLEN] [-k KIND] - [--norm NORM] [--noclobber] [-o OUTROOT] [--back BACK] - [--save-dyn] [--ignore-instr] [--ignore-gtis] [--save-all] - [--save-lcs] [--no-auxil] [--test] [--emin EMIN] [--emax EMAX] + usage: HENfspec [-h] [-b BINTIME] [-r REBIN] [-f FFTLEN] [-k KIND] [--norm NORM] [--noclobber] + [-o OUTROOT] [--back BACK] [--save-dyn] [--ignore-instr] [--ignore-gtis] + [--save-all] [--save-lcs] [--no-auxil] [--test] [--emin EMIN] [--emax EMAX] [--lombscargle] [--loglevel LOGLEVEL] [--debug] files [files ...] - Create frequency spectra (PDS, CPDS, cospectrum) starting from well-defined - input ligthcurves + Create frequency spectra (PDS, CPDS, cospectrum) starting from well-defined input ligthcurves positional arguments: files List of light curve files @@ -532,17 +488,15 @@ HENfspec options: -h, --help show this help message and exit -b BINTIME, --bintime BINTIME - Light curve bin time; if negative, interpreted as - negative power of 2. Default: 2^-10, or keep input lc - bin time (whatever is larger) + Light curve bin time; if negative, interpreted as negative power of 2. + Default: 2^-10, or keep input lc bin time (whatever is larger) -r REBIN, --rebin REBIN (C)PDS rebinning to apply. Default: none -f FFTLEN, --fftlen FFTLEN Length of FFTs. Default: 512 s - -k KIND, --kind KIND Spectra to calculate, as comma-separated list - (Accepted: PDS and CPDS; Default: "PDS,CPDS") - --norm NORM Normalization to use (Accepted: leahy and rms; - Default: "leahy") + -k KIND, --kind KIND Spectra to calculate, as comma-separated list (Accepted: PDS and CPDS; + Default: "PDS,CPDS") + --norm NORM Normalization to use (Accepted: leahy and rms; Default: "leahy") --noclobber Do not overwrite existing files -o OUTROOT, --outroot OUTROOT Root of output file names for CPDS only @@ -550,19 +504,16 @@ HENfspec --save-dyn save dynamical power spectrum --ignore-instr Ignore instrument names in channels --ignore-gtis Ignore GTIs. USE AT YOUR OWN RISK - --save-all Save all information contained in spectra, including - light curves and dynamical spectra. - --save-lcs Save all information contained in spectra, including - light curves. - --no-auxil Do not save auxiliary spectra (e.g. pds1 and pds2 of - cross spectrum) + --save-all Save all information contained in spectra, including light curves and + dynamical spectra. + --save-lcs Save all information contained in spectra, including light curves. + --no-auxil Do not save auxiliary spectra (e.g. pds1 and pds2 of cross spectrum) --test Only to be used in testing --emin EMIN Minimum energy (or PI if uncalibrated) to plot --emax EMAX Maximum energy (or PI if uncalibrated) to plot - --lombscargle Use Lomb-Scargle periodogram or cross spectrum (will - ignore segment_size) - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --lombscargle Use Lomb-Scargle periodogram or cross spectrum (will ignore segment_size) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -573,8 +524,7 @@ HENjoinevents usage: HENjoinevents [-h] [-o OUTPUT] [--ignore-instr] files [files ...] - Read a cleaned event files and saves the relevant information in a standard - format + Read a cleaned event files and saves the relevant information in a standard format positional arguments: files Files to join @@ -600,8 +550,8 @@ HENlags options: -h, --help show this help message and exit - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -610,18 +560,15 @@ HENlcurve :: - usage: HENlcurve [-h] [-b BINTIME] - [--safe-interval SAFE_INTERVAL SAFE_INTERVAL] - [-e ENERGY_INTERVAL ENERGY_INTERVAL] - [--pi-interval PI_INTERVAL PI_INTERVAL] [-s] [-j] [-g] - [--minlen MINLEN] [--ignore-gtis] [-d OUTDIR] [--noclobber] - [--fits-input] [--txt-input] [--weight-on WEIGHT_ON] - [-p DEORBIT_PAR] [-o OUTFILE] [--loglevel LOGLEVEL] [--debug] - [--nproc NPROC] + usage: HENlcurve [-h] [-b BINTIME] [--safe-interval SAFE_INTERVAL SAFE_INTERVAL] + [-e ENERGY_INTERVAL ENERGY_INTERVAL] [--pi-interval PI_INTERVAL PI_INTERVAL] [-s] + [-j] [-g] [--minlen MINLEN] [--ignore-gtis] [-d OUTDIR] [--noclobber] + [--fits-input] [--txt-input] [--weight-on WEIGHT_ON] [-p DEORBIT_PAR] [-o OUTFILE] + [--loglevel LOGLEVEL] [--debug] [--nproc NPROC] files [files ...] - Create lightcurves starting from event files. It is possible to specify energy - or channel filtering options + Create lightcurves starting from event files. It is possible to specify energy or channel filtering + options positional arguments: files List of files @@ -647,15 +594,13 @@ HENlcurve --fits-input Input files are light curves in FITS format --txt-input Input files are light curves in txt format --weight-on WEIGHT_ON - Use a given attribute of the event list as weights for - the light curve + Use a given attribute of the event list as weights for the light curve -p DEORBIT_PAR, --deorbit-par DEORBIT_PAR - Deorbit data with this parameter file (requires PINT - installed) + Deorbit data with this parameter file (requires PINT installed) -o OUTFILE, --outfile OUTFILE Output file - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level --nproc NPROC Number of processors to use @@ -678,18 +623,16 @@ HENmodel options: -h, --help show this help message and exit -m MODELFILE, --modelfile MODELFILE - File containing an Astropy model with or without - constraints + File containing an Astropy model with or without constraints --fitmethod FITMETHOD Any scipy-compatible fit method --frequency-interval FREQUENCY_INTERVAL [FREQUENCY_INTERVAL ...] - Select frequency interval(s) to fit. Must be an even - number of frequencies in Hz, like "--frequency- - interval 0 2" or "--frequency-interval 0 2 5 10", - meaning that the spectrum will be fitted between 0 and - 2 Hz, or using the intervals 0-2 Hz and 5-10 Hz. - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + Select frequency interval(s) to fit. Must be an even number of frequencies + in Hz, like "--frequency-interval 0 2" or "--frequency-interval 0 2 5 10", + meaning that the spectrum will be fitted between 0 and 2 Hz, or using the + intervals 0-2 Hz and 5-10 Hz. + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -698,13 +641,12 @@ HENphaseogram :: - usage: HENphaseogram [-h] [-f FREQ] [--fdot FDOT] [--fddot FDDOT] - [--periodogram PERIODOGRAM] [-n NBIN] [--ntimes NTIMES] - [--binary] + usage: HENphaseogram [-h] [-f FREQ] [--fdot FDOT] [--fddot FDDOT] [--periodogram PERIODOGRAM] + [-n NBIN] [--ntimes NTIMES] [--binary] [--binary-parameters BINARY_PARAMETERS BINARY_PARAMETERS BINARY_PARAMETERS] - [--emin EMIN] [--emax EMAX] [--plot-only] [--get-toa] - [--pepoch PEPOCH] [--norm NORM] [--colormap COLORMAP] - [-p DEORBIT_PAR] [--test] [--loglevel LOGLEVEL] [--debug] + [--emin EMIN] [--emax EMAX] [--plot-only] [--get-toa] [--pepoch PEPOCH] + [--norm NORM] [--colormap COLORMAP] [-p DEORBIT_PAR] [--test] + [--loglevel LOGLEVEL] [--debug] file Plot an interactive phaseogram @@ -721,8 +663,7 @@ HENphaseogram Periodogram file -n NBIN, --nbin NBIN Number of phase bins (X axis) of the profile --ntimes NTIMES Number of time bins (Y axis) of the phaseogram - --binary Interact on binary parameters instead of frequency - derivatives + --binary Interact on binary parameters instead of frequency derivatives --binary-parameters BINARY_PARAMETERS BINARY_PARAMETERS BINARY_PARAMETERS Initial values for binary parameters --emin EMIN Minimum energy (or PI if uncalibrated) to plot @@ -730,24 +671,19 @@ HENphaseogram --plot-only Only plot the phaseogram --get-toa Only calculate TOAs --pepoch PEPOCH Reference epoch for timing parameters (MJD) - --norm NORM Normalization for the dynamical phase plot. Can be: - 'to1' (each profile normalized from 0 to 1); 'std' - (subtract the mean and divide by the standard - deviation); 'sub' (just subtract the mean of each - profile); 'ratios' (divide by the average profile, to - highlight changes). Prepending 'median' to any of - those options uses the median in place of the mean. - Appending '_smooth' smooths the 2d array with a - Gaussian filter. E.g. mediansub_smooth subtracts the - median and smooths the imagedefault None - --colormap COLORMAP Change the color map of the image. Any matplotlib - colormap is valid + --norm NORM Normalization for the dynamical phase plot. Can be: 'to1' (each profile + normalized from 0 to 1); 'std' (subtract the mean and divide by the standard + deviation); 'sub' (just subtract the mean of each profile); 'ratios' (divide + by the average profile, to highlight changes). Prepending 'median' to any of + those options uses the median in place of the mean. Appending '_smooth' + smooths the 2d array with a Gaussian filter. E.g. mediansub_smooth subtracts + the median and smooths the imagedefault None + --colormap COLORMAP Change the color map of the image. Any matplotlib colormap is valid -p DEORBIT_PAR, --deorbit-par DEORBIT_PAR - Deorbit data with this parameter file (requires PINT - installed) + Deorbit data with this parameter file (requires PINT installed) --test Only used for tests - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -756,9 +692,8 @@ HENphasetag :: - usage: HENphasetag [-h] [--parfile PARFILE] [-f FREQS [FREQS ...]] [-n NBIN] - [--plot] [--tomax] [--test] [--refTOA PULSE_REF_TIME] - [--pepoch PEPOCH] + usage: HENphasetag [-h] [--parfile PARFILE] [-f FREQS [FREQS ...]] [-n NBIN] [--plot] [--tomax] + [--test] [--refTOA PULSE_REF_TIME] [--pepoch PEPOCH] file positional arguments: @@ -774,8 +709,7 @@ HENphasetag --tomax Refer phase to pulse max --test Only for unit tests! Do not use --refTOA PULSE_REF_TIME - Reference TOA in MJD (overrides --tomax) for reference - pulse phase + Reference TOA in MJD (overrides --tomax) for reference pulse phase --pepoch PEPOCH Reference time for timing solution @@ -784,9 +718,8 @@ HENplot :: - usage: HENplot [-h] [--noplot] [--CCD] [--HID] [--figname FIGNAME] - [-o OUTFILE] [--xlog] [--ylog] [--xlin] [--ylin] [--white-sub] - [--fromstart] [--axes AXES AXES] + usage: HENplot [-h] [--noplot] [--CCD] [--HID] [--figname FIGNAME] [-o OUTFILE] [--xlog] [--ylog] + [--xlin] [--ylin] [--white-sub] [--fromstart] [--axes AXES AXES] files [files ...] Plot the content of HENDRICS light curves and frequency spectra @@ -797,12 +730,10 @@ HENplot options: -h, --help show this help message and exit --noplot Only create images, do not plot - --CCD This is a color-color diagram. In this case, the list - of files is expected to be given as soft0.nc, - hard0.nc, soft1.nc, hard1.nc, ... - --HID This is a hardness-intensity diagram. In this case, - the list of files is expected to be given as - color0.nc, intensity0.nc, color1.nc, intensity1.nc, + --CCD This is a color-color diagram. In this case, the list of files is expected + to be given as soft0.nc, hard0.nc, soft1.nc, hard1.nc, ... + --HID This is a hardness-intensity diagram. In this case, the list of files is + expected to be given as color0.nc, intensity0.nc, color1.nc, intensity1.nc, ... --figname FIGNAME Figure name -o OUTFILE, --outfile OUTFILE @@ -812,8 +743,8 @@ HENplot --xlin Use linear X axis --ylin Use linear Y axis --white-sub Subtract Poisson noise (only applies to PDS) - --fromstart Times are measured from the start of the observation - (only relevant for light curves) + --fromstart Times are measured from the start of the observation (only relevant for + light curves) --axes AXES AXES Plot two variables contained in the file @@ -824,9 +755,8 @@ HENpowercolors usage: HENpowercolors [-h] [-f FREQUENCY_EDGES FREQUENCY_EDGES FREQUENCY_EDGES FREQUENCY_EDGES FREQUENCY_EDGES] - [-r REBIN] [-s SEGMENT_SIZE] - [--poisson-noise POISSON_NOISE] [-b BINTIME] [--cross] - [-o OUTFILE] [--loglevel LOGLEVEL] [--debug] + [-r REBIN] [-s SEGMENT_SIZE] [--poisson-noise POISSON_NOISE] [-b BINTIME] + [--cross] [-o OUTFILE] [--loglevel LOGLEVEL] [--debug] files [files ...] Calculate color light curves @@ -837,26 +767,24 @@ HENpowercolors options: -h, --help show this help message and exit -f FREQUENCY_EDGES FREQUENCY_EDGES FREQUENCY_EDGES FREQUENCY_EDGES FREQUENCY_EDGES, --frequency-edges FREQUENCY_EDGES FREQUENCY_EDGES FREQUENCY_EDGES FREQUENCY_EDGES FREQUENCY_EDGES - Five frequency edges in Hz, delimiting four frequency - ranges used to calculate the power colors + Five frequency edges in Hz, delimiting four frequency ranges used to + calculate the power colors -r REBIN, --rebin REBIN - Dynamical power spectrum rebinning (how many nearby - segments to average before calculating the colors) to - apply. Default: 5 + Dynamical power spectrum rebinning (how many nearby segments to average + before calculating the colors) to apply. Default: 5 -s SEGMENT_SIZE, --segment-size SEGMENT_SIZE Length of FFTs. Default: 512 s --poisson-noise POISSON_NOISE - Poisson noise level of the periodograms. Default: 2 - for powerspectrum, 0 for crossspectrum + Poisson noise level of the periodograms. Default: 2 for powerspectrum, 0 for + crossspectrum -b BINTIME, --bintime BINTIME - Light curve bin time; if negative, interpreted as - negative power of 2. Default: 2^-10, or keep input lc - bin time (whatever is larger) + Light curve bin time; if negative, interpreted as negative power of 2. + Default: 2^-10, or keep input lc bin time (whatever is larger) --cross Use cross spectrum from pairs of files -o OUTFILE, --outfile OUTFILE Output file - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -865,16 +793,15 @@ HENreadevents :: - usage: HENreadevents [-h] [--noclobber] [-g] [--discard-calibration] + usage: HENreadevents [-h] [--noclobber] [-g] [--discard-calibration] [--ignore-detectors] [-l LENGTH_SPLIT] [--min-length MIN_LENGTH] + [--bin-time-for-occultations BIN_TIME_FOR_OCCULTATIONS] [--gti-string GTI_STRING] [--randomize-by RANDOMIZE_BY] - [--fill-small-gaps FILL_SMALL_GAPS] - [--additional ADDITIONAL [ADDITIONAL ...]] [-o OUTFILE] - [--loglevel LOGLEVEL] [--debug] [--nproc NPROC] + [--fill-small-gaps FILL_SMALL_GAPS] [--additional ADDITIONAL [ADDITIONAL ...]] + [-o OUTFILE] [--loglevel LOGLEVEL] [--debug] [--nproc NPROC] files [files ...] - Read a cleaned event files and saves the relevant information in a standard - format + Read a cleaned event files and saves the relevant information in a standard format positional arguments: files List of files @@ -885,24 +812,28 @@ HENreadevents -g, --gti-split Split event list by GTI --discard-calibration Discard automatic calibration (if any) + --ignore-detectors Do not split by detector -l LENGTH_SPLIT, --length-split LENGTH_SPLIT Split event list by length --min-length MIN_LENGTH Minimum length of GTIs to consider + --bin-time-for-occultations BIN_TIME_FOR_OCCULTATIONS + Create a light curve with this bin time and infer occultations not recorded + in GTIs. (The flux drops to zero and the average count rate is significantly + above 25 ct/s) --gti-string GTI_STRING GTI string --randomize-by RANDOMIZE_BY - Randomize event arrival times by this amount (e.g. it - might be the 0.073-s frame time in XMM) + Randomize event arrival times by this amount (e.g. it might be the 0.073-s + frame time in XMM) --fill-small-gaps FILL_SMALL_GAPS - Fill gaps between GTIs with random data, if shorter - than this amount + Fill gaps between GTIs with random data, if shorter than this amount --additional ADDITIONAL [ADDITIONAL ...] Additional columns to be read from the FITS file -o OUTFILE, --outfile OUTFILE Output file - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level --nproc NPROC Number of processors to use @@ -929,8 +860,7 @@ HENrebin :: - usage: HENrebin [-h] [-r REBIN] [--loglevel LOGLEVEL] [--debug] - files [files ...] + usage: HENrebin [-h] [-r REBIN] [--loglevel LOGLEVEL] [--debug] files [files ...] Rebin light curves and frequency spectra. @@ -940,12 +870,11 @@ HENrebin options: -h, --help show this help message and exit -r REBIN, --rebin REBIN - Rebinning to apply. Only if the quantity to rebin is a - (C)PDS, it is possible to specify a non-integer rebin - factor, in which case it is interpreted as a - geometrical binning factor - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + Rebinning to apply. Only if the quantity to rebin is a (C)PDS, it is + possible to specify a non-integer rebin factor, in which case it is + interpreted as a geometrical binning factor + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -954,16 +883,13 @@ HENscramble :: - usage: HENscramble [-h] [--smooth-kind {smooth,flat,pulsed}] - [--deadtime DEADTIME] [--dt DT] - [--pulsed-fraction PULSED_FRACTION] [-f FREQUENCY] - [--outfile OUTFILE] [-p DEORBIT_PAR] - [-e ENERGY_INTERVAL ENERGY_INTERVAL] [--loglevel LOGLEVEL] + usage: HENscramble [-h] [--smooth-kind {smooth,flat,pulsed}] [--deadtime DEADTIME] [--dt DT] + [--pulsed-fraction PULSED_FRACTION] [-f FREQUENCY] [--outfile OUTFILE] + [-p DEORBIT_PAR] [-e ENERGY_INTERVAL ENERGY_INTERVAL] [--loglevel LOGLEVEL] [--debug] fname - Scramble the events inside an event list, maintaining the same energies and - GTIs + Scramble the events inside an event list, maintaining the same energies and GTIs positional arguments: fname File containing input event list @@ -972,9 +898,8 @@ HENscramble -h, --help show this help message and exit --smooth-kind {smooth,flat,pulsed} Special testing value - --deadtime DEADTIME Dead time magnitude. Can be specified as a single - number, or two. In this last case, the second value is - used as sigma of the dead time distribution + --deadtime DEADTIME Dead time magnitude. Can be specified as a single number, or two. In this + last case, the second value is used as sigma of the dead time distribution --dt DT Time resolution of smoothed light curve --pulsed-fraction PULSED_FRACTION Pulsed fraction of simulated pulsations @@ -982,12 +907,11 @@ HENscramble Pulsed fraction of simulated pulsations --outfile OUTFILE Output file name -p DEORBIT_PAR, --deorbit-par DEORBIT_PAR - Deorbit data with this parameter file (requires PINT - installed) + Deorbit data with this parameter file (requires PINT installed) -e ENERGY_INTERVAL ENERGY_INTERVAL, --energy-interval ENERGY_INTERVAL ENERGY_INTERVAL Energy interval used for filtering - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -996,8 +920,7 @@ HENscrunchlc :: - usage: HENscrunchlc [-h] [-o OUT] [--loglevel LOGLEVEL] [--debug] - files [files ...] + usage: HENscrunchlc [-h] [-o OUT] [--loglevel LOGLEVEL] [--debug] files [files ...] Sum lightcurves from different instruments or energy ranges @@ -1007,8 +930,8 @@ HENscrunchlc options: -h, --help show this help message and exit -o OUT, --out OUT Output file - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug use DEBUG logging level @@ -1017,12 +940,9 @@ HENsplitevents :: - usage: HENsplitevents [-h] [-l LENGTH_SPLIT] [--overlap OVERLAP] - [--split-at-mjd SPLIT_AT_MJD] - fname + usage: HENsplitevents [-h] [-l LENGTH_SPLIT] [--overlap OVERLAP] [--split-at-mjd SPLIT_AT_MJD] fname - Reads a cleaned event files and splits the file into overlapping multiple - chunks of fixed length + Reads a cleaned event files and splits the file into overlapping multiple chunks of fixed length positional arguments: fname File 1 @@ -1031,8 +951,7 @@ HENsplitevents -h, --help show this help message and exit -l LENGTH_SPLIT, --length-split LENGTH_SPLIT Split event list by GTI - --overlap OVERLAP Overlap factor. 0 for no overlap, 0.5 for half- - interval overlap, and so on. + --overlap OVERLAP Overlap factor. 0 for no overlap, 0.5 for half-interval overlap, and so on. --split-at-mjd SPLIT_AT_MJD Split at this MJD @@ -1052,8 +971,7 @@ HENsumfspec options: -h, --help show this help message and exit -o OUTNAME, --outname OUTNAME - Output file name for summed (C)PDS. Default: - tot_(c)pds.nc + Output file name for summed (C)PDS. Default: tot_(c)pds.p HENvarenergy @@ -1063,11 +981,9 @@ HENvarenergy usage: HENvarenergy [-h] [-f FREQ_INTERVAL FREQ_INTERVAL] [--energy-values ENERGY_VALUES ENERGY_VALUES ENERGY_VALUES ENERGY_VALUES] - [--segment-size SEGMENT_SIZE] - [--ref-band REF_BAND REF_BAND] [--rms] [--covariance] - [--use-pi] [--cross-instr] [--lag] [--count] - [--label LABEL] [--norm NORM] [--format FORMAT] - [-b BINTIME] [--loglevel LOGLEVEL] [--debug] + [--segment-size SEGMENT_SIZE] [--ref-band REF_BAND REF_BAND] [--rms] + [--covariance] [--use-pi] [--cross-instr] [--lag] [--count] [--label LABEL] + [--norm NORM] [--format FORMAT] [-b BINTIME] [--loglevel LOGLEVEL] [--debug] files [files ...] Calculates variability-energy spectra @@ -1078,10 +994,9 @@ HENvarenergy options: -h, --help show this help message and exit -f FREQ_INTERVAL FREQ_INTERVAL, --freq-interval FREQ_INTERVAL FREQ_INTERVAL - Frequence interval + Frequency interval --energy-values ENERGY_VALUES ENERGY_VALUES ENERGY_VALUES ENERGY_VALUES - Choose Emin, Emax, number of intervals,interval - spacing, lin or log + Choose Emin, Emax, number of intervals,interval spacing, lin or log --segment-size SEGMENT_SIZE Length of the light curve intervals to be averaged --ref-band REF_BAND REF_BAND @@ -1089,20 +1004,19 @@ HENvarenergy --rms Calculate rms --covariance Calculate covariance spectrum --use-pi Energy intervals are specified as PI channels - --cross-instr Use data files in pairs, for example with thereference - band from one and the subbands from the other (useful - in NuSTAR and multiple-detector missions) + --cross-instr Use data files in pairs, for example with thereference band from one and the + subbands from the other (useful in NuSTAR and multiple-detector missions) --lag Calculate lag-energy --count Calculate lag-energy --label LABEL Additional label to be added to file names - --norm NORM When relevant, the normalization of the spectrum. One - of ['abs', 'frac', 'rms', 'leahy', 'none'] - --format FORMAT Output format for the table. Can be ECSV, QDP, or any - other format accepted by astropy + --norm NORM When relevant, the normalization of the spectrum. One of ['abs', 'frac', + 'rms', 'leahy', 'none'] + --format FORMAT Output format for the table. Can be ECSV, QDP, or any other format accepted + by astropy -b BINTIME, --bintime BINTIME Bin time - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -1112,15 +1026,13 @@ HENz2vspf :: usage: HENz2vspf [-h] [--ntrial NTRIAL] [--outfile OUTFILE] - [--show-z-values SHOW_Z_VALUES [SHOW_Z_VALUES ...]] - [--emin EMIN] [--emax EMAX] [-N N] [--loglevel LOGLEVEL] - [--debug] + [--show-z-values SHOW_Z_VALUES [SHOW_Z_VALUES ...]] [--emin EMIN] [--emax EMAX] + [-N N] [--loglevel LOGLEVEL] [--debug] fname - Get Z2 vs pulsed fraction for a given observation. Takes the original event - list, scrambles the event arrival time, adds a pulsation with random pulsed - fraction, and takes the maximum value of Z2 in a small interval around the - pulsation. Does this ntrial times, and plots. + Get Z2 vs pulsed fraction for a given observation. Takes the original event list, scrambles the + event arrival time, adds a pulsation with random pulsed fraction, and takes the maximum value of Z2 + in a small interval around the pulsation. Does this ntrial times, and plots. positional arguments: fname Input file name @@ -1134,8 +1046,8 @@ HENz2vspf --emin EMIN Minimum energy (or PI if uncalibrated) to plot --emax EMAX Maximum energy (or PI if uncalibrated) to plot -N N The N in Z^2_N - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level @@ -1144,17 +1056,14 @@ HENzsearch :: - usage: HENzsearch [-h] -f FMIN -F FMAX [--emin EMIN] [--emax EMAX] - [--mean-fdot MEAN_FDOT] [--mean-fddot MEAN_FDDOT] - [--fdotmin FDOTMIN] [--fdotmax FDOTMAX] [--dynstep DYNSTEP] - [--npfact NPFACT] + usage: HENzsearch [-h] -f FMIN -F FMAX [--emin EMIN] [--emax EMAX] [--mean-fdot MEAN_FDOT] + [--mean-fddot MEAN_FDDOT] [--fdotmin FDOTMIN] [--fdotmax FDOTMAX] + [--dynstep DYNSTEP] [--npfact NPFACT] [--n-transient-intervals N_TRANSIENT_INTERVALS] [-n NBIN] - [--segment-size SEGMENT_SIZE] [--step STEP] - [--oversample OVERSAMPLE] [--fast] [--ffa] [--transient] - [--expocorr] [--find-candidates] [--conflevel CONFLEVEL] - [--fit-candidates] [--curve CURVE] - [--fit-frequency FIT_FREQUENCY] [-N N] [-p DEORBIT_PAR] - [--loglevel LOGLEVEL] [--debug] + [--segment-size SEGMENT_SIZE] [--step STEP] [--oversample OVERSAMPLE] [--fast] + [--ffa] [--transient] [--expocorr] [--find-candidates] [--conflevel CONFLEVEL] + [--fit-candidates] [--curve CURVE] [--fit-frequency FIT_FREQUENCY] [-N N] + [-p DEORBIT_PAR] [--loglevel LOGLEVEL] [--debug] files [files ...] Search for pulsars using the epoch folding or the Z_n^2 algorithm @@ -1180,27 +1089,23 @@ HENzsearch Number of transient intervals to investigate -n NBIN, --nbin NBIN Number of phase bins of the profile --segment-size SEGMENT_SIZE - Size of the event list segment to use (default None, - implying the whole observation) - --step STEP Step size of the frequency axis. Defaults to - 1/oversample/obs_length. + Size of the event list segment to use (default None, implying the whole + observation) + --step STEP Step size of the frequency axis. Defaults to 1/oversample/obs_length. --oversample OVERSAMPLE - Oversampling factor - frequency resolution improvement - w.r.t. the standard FFT's 1/obs_length. - --fast Use a faster folding algorithm. It automatically - searches for the first spin derivative using an - optimized step.This option ignores expocorr, + Oversampling factor - frequency resolution improvement w.r.t. the standard + FFT's 1/obs_length. + --fast Use a faster folding algorithm. It automatically searches for the first spin + derivative using an optimized step.This option ignores expocorr, fdotmin/max, segment-size, and step - --ffa Use *the* Fast Folding Algorithm by Staelin+69. No - accelerated search allowed at the moment. Only - recommended to search for slow pulsars. - --transient Look for transient emission (produces an animated GIF - with the dynamic Z search) - --expocorr Correct for the exposure of the profile bins. This - method is *much* slower, but it is useful for very - slow pulsars, where data gaps due to occultation or - SAA passages can significantly alter the exposure of - different profile bins. + --ffa Use *the* Fast Folding Algorithm by Staelin+69. No accelerated search + allowed at the moment. Only recommended to search for slow pulsars. + --transient Look for transient emission (produces an animated GIF with the dynamic Z + search) + --expocorr Correct for the exposure of the profile bins. This method is *much* slower, + but it is useful for very slow pulsars, where data gaps due to occultation + or SAA passages can significantly alter the exposure of different profile + bins. --find-candidates Find pulsation candidates using thresholding --conflevel CONFLEVEL percent confidence level for thresholding [0-100). @@ -1208,11 +1113,12 @@ HENzsearch --curve CURVE Kind of curve to use (sinc or Gaussian) --fit-frequency FIT_FREQUENCY Force the candidate frequency to FIT_FREQUENCY - -N N The number of harmonics to use in the search (the 'N' - in Z^2_N; only relevant to Z search!) + -N N The number of harmonics to use in the search (the 'N' in Z^2_N; only + relevant to Z search!) -p DEORBIT_PAR, --deorbit-par DEORBIT_PAR - Deorbit data with this parameter file (requires PINT - installed) - --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, - ERROR, CRITICAL, DEBUG; default:WARNING) + Deorbit data with this parameter file (requires PINT installed) + --loglevel LOGLEVEL use given logging level (one between INFO, WARNING, ERROR, CRITICAL, DEBUG; + default:WARNING) --debug set DEBUG logging level + + diff --git a/hendrics/base.py b/hendrics/base.py index f70c2fab..0af92cd3 100644 --- a/hendrics/base.py +++ b/hendrics/base.py @@ -60,50 +60,50 @@ def show_progress(a): ) __all__ = [ - "array_take", - "njit", - "prange", - "show_progress", - "z2_n_detection_level", - "z2_n_probability", - "pds_detection_level", - "pds_probability", - "fold_detection_level", - "fold_profile_probability", - "r_in", - "r_det", + "_add_default_args", "_assign_value_if_none", "_look_for_array_in_array", - "is_string", "_order_list_of_arrays", - "mkdir_p", + "adjust_dt_for_power_of_two", + "adjust_dt_for_small_power", + "array_take", + "check_negative_numbers_in_args", "common_name", - "hen_root", - "optimal_bin_time", - "gti_len", + "compute_bin", "deorbit_events", - "_add_default_args", - "check_negative_numbers_in_args", - "interpret_bintime", + "fold_detection_level", + "fold_profile_probability", "get_bin_edges", - "compute_bin", + "get_list_of_small_powers", + "gti_len", + "hen_root", "hist1d_numba_seq", "hist2d_numba_seq", - "hist3d_numba_seq", "hist2d_numba_seq_weight", + "hist3d_numba_seq", "hist3d_numba_seq_weight", - "index_arr", - "index_set_arr", "histnd_numba_seq", - "histogram2d", "histogram", - "touch", + "histogram2d", + "index_arr", + "index_set_arr", + "interpret_bintime", + "is_string", "log_x", - "get_list_of_small_powers", - "adjust_dt_for_power_of_two", - "adjust_dt_for_small_power", "memmapped_arange", + "mkdir_p", "nchars_in_int_value", + "njit", + "optimal_bin_time", + "pds_detection_level", + "pds_probability", + "prange", + "r_det", + "r_in", + "show_progress", + "touch", + "z2_n_detection_level", + "z2_n_probability", ] diff --git a/hendrics/ffa.py b/hendrics/ffa.py index 642f0af7..3682f85f 100644 --- a/hendrics/ffa.py +++ b/hendrics/ffa.py @@ -2,7 +2,10 @@ import numpy as np -from .base import float32, float64, int32, int64, njit, show_progress, vectorize +from . import float32, float64, int32, int64, njit, vectorize +from .base import show_progress + +__all__ = ["ffa_search", "h_test", "z_n_fast_cached", "z_n_fast_cached_all"] """ prof_n step0 step1 step2 diff --git a/hendrics/io.py b/hendrics/io.py index 32ef7ab2..48f1eb4d 100644 --- a/hendrics/io.py +++ b/hendrics/io.py @@ -1216,7 +1216,7 @@ def print_fits_info(fits_file, hdu=1): print(f"Date (MJD): {start_mjd} -- {stop_mjd}\n") print(f"Instrument: {info['Telescope']}/{info['Instrument']}\n") print(f"Target: {info['Target']}\n") - print(f"N. Events: {info["N. events"]}\n") + print(f"N. Events: {info['N. events']}\n") lchdulist.close() return info diff --git a/hendrics/ml_timing.py b/hendrics/ml_timing.py index d2cdad42..774cd579 100644 --- a/hendrics/ml_timing.py +++ b/hendrics/ml_timing.py @@ -4,7 +4,7 @@ from scipy.interpolate import interp1d from scipy.optimize import minimize -from .base import float32, float64, int64, njit, vectorize +from . import float32, float64, int64, njit, vectorize try: from statsmodels.tools.numdiff import approx_hess3 diff --git a/pyproject.toml b/pyproject.toml index 9cc1d8c9..c92cf9ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,6 +80,7 @@ docs = [ "jinja2==3.1.3", "docutils", "sphinx-astropy", + "sphinx-toolbox", "nbsphinx>=0.8.3,!=0.8.8", "nbconvert<7.14", "pandoc", @@ -92,6 +93,43 @@ homepage = "https://stingray.science" documentation = "https://hendrics.stingray.science" repository = "https://github.com/stingraysoftware/hendrics" + +[project.scripts] +HEN2xspec = "hendrics.save_as_xspec:main" +HENaccelsearch = "hendrics.efsearch:main_accelsearch" +HENbaseline = "hendrics.lcurve:baseline_main" +HENbinary = "hendrics.binary:main_presto" +HENcalibrate = "hendrics.calibrate:main" +HENcolors = "hendrics.colors:main" +HENcreategti = "hendrics.create_gti:main" +HENdeorbit = "hendrics.fold:main_deorbit" +HENdumpdyn = "hendrics.fspec:dumpdyn_main" +HENefsearch = "hendrics.efsearch:main_efsearch" +HENexcvar = "hendrics.exvar:main" +HENexposure = "hendrics.exposure:main" +HENfake = "hendrics.fake:main" +HENfiltevents = "hendrics.io:main_filter_events" +HENfold = "hendrics.fold:main_fold" +HENfspec = "hendrics.fspec:main" +HENjoinevents = "hendrics.read_events:main_join" +HENlags = "hendrics.timelags:main" +HENlcurve = "hendrics.lcurve:main" +HENmodel = "hendrics.modeling:main_model" +HENphaseogram = "hendrics.phaseogram:main_phaseogram" +HENphasetag = "hendrics.phasetag:main_phasetag" +HENplot = "hendrics.plot:main" +HENpowercolors = "hendrics.power_colors:main" +HENreadevents = "hendrics.read_events:main" +HENreadfile = "hendrics.io:main" +HENrebin = "hendrics.rebin:main" +HENscramble = "hendrics.fake:main_scramble" +HENscrunchlc = "hendrics.lcurve:scrunch_main" +HENsplitevents = "hendrics.read_events:main_splitevents" +HENsumfspec = "hendrics.sum_fspec:main" +HENvarenergy = "hendrics.varenergy:main" +HENz2vspf = "hendrics.efsearch:main_z2vspf" +HENzsearch = "hendrics.efsearch:main_zsearch" + [build-system] requires = ["setuptools", "setuptools_scm", @@ -116,7 +154,7 @@ namespaces = false "*.rmf", ] "hendrics.compat" = ["datasets/*"] -"hendrics.tests" = "data/*" +"hendrics.tests" = ["data/*"] [tool.setuptools_scm] write_to = "hendrics/_version.py" From 67921a2893db4eed5f081d0537067474ef20ba5d Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 11:12:16 +0200 Subject: [PATCH 40/58] Fix many tests --- hendrics/fspec.py | 1 + hendrics/lcurve.py | 2 +- hendrics/rebin.py | 4 +- hendrics/tests/__init__.py | 6 +- hendrics/tests/test_a_complete_run.py | 72 ++++++++------ hendrics/tests/test_base.py | 2 +- hendrics/tests/test_binary.py | 17 ++-- hendrics/tests/test_calibrate.py | 20 ++-- hendrics/tests/test_colors.py | 24 ++--- hendrics/tests/test_efsearch.py | 3 +- hendrics/tests/test_fake.py | 63 ++++++------ hendrics/tests/test_fspec.py | 129 +++++++++++++------------ hendrics/tests/test_gti.py | 25 +++-- hendrics/tests/test_io.py | 1 + hendrics/tests/test_lc.py | 132 ++++++++++++++------------ hendrics/tests/test_phaseogram.py | 2 +- hendrics/tests/test_read_events.py | 44 ++++----- 17 files changed, 297 insertions(+), 250 deletions(-) diff --git a/hendrics/fspec.py b/hendrics/fspec.py index b4b0385b..74a0a3d4 100644 --- a/hendrics/fspec.py +++ b/hendrics/fspec.py @@ -151,6 +151,7 @@ def _distribute_events(events, chunk_length): Examples -------- + >>> from stingray import EventList >>> ev = EventList([1, 2, 3, 4, 5, 6], gti=[[0.5, 6.5]]) >>> ev.pi = np.ones_like(ev.time) >>> ev.mjdref = 56780. diff --git a/hendrics/lcurve.py b/hendrics/lcurve.py index 06b66d7f..d532a0a3 100644 --- a/hendrics/lcurve.py +++ b/hendrics/lcurve.py @@ -389,7 +389,7 @@ def lcurve_from_events( es = evdata.energy good = np.logical_and(es > e_interval[0], es <= e_interval[1]) events = events[good] - tag = f"_E{e_interval[0]}-{e_interval[1]}" + tag = f"_E{e_interval[0]:g}-{e_interval[1]:g}" else: pass diff --git a/hendrics/rebin.py b/hendrics/rebin.py index 2c0ae727..e6fe8349 100644 --- a/hendrics/rebin.py +++ b/hendrics/rebin.py @@ -26,7 +26,9 @@ def rebin_file(filename, rebin): func = save_pds options = {"save_all": True} - outfile = filename.replace(get_file_extension(filename), f"_rebin{rebin}" + HEN_FILE_EXTENSION) + outfile = filename.replace( + get_file_extension(filename), f"_rebin{rebin:g}" + HEN_FILE_EXTENSION + ) log.info(f"Saving {ftype} to {outfile}") func(contents, outfile, **options) diff --git a/hendrics/tests/__init__.py b/hendrics/tests/__init__.py index 523867c4..605318a4 100644 --- a/hendrics/tests/__init__.py +++ b/hendrics/tests/__init__.py @@ -25,7 +25,7 @@ def _dummy_par(par, pb=1e20, a1=0.0, f0=1.0): def find_file_pattern_in_dir(pattern, directory): - return Path(directory).glob(pattern) + return [str(p) for p in Path(directory).glob(pattern)] def cleanup_test_dir(datadir): @@ -55,10 +55,10 @@ def cleanup_test_dir(datadir): for f in file_list: f = Path(f) if f.exists() and not f.is_dir(): - print("Removing " + f) + print(f"Removing {f}") f.unlink() elif f.exists() and f.is_dir(): - print("Removing directory " + f) + print(f"Removing directory {f}") shutil.rmtree(str(f)) patterns = ["*_pds*/", "*_cpds*/", "*_sum/"] diff --git a/hendrics/tests/test_a_complete_run.py b/hendrics/tests/test_a_complete_run.py index 4836209b..43f3914d 100644 --- a/hendrics/tests/test_a_complete_run.py +++ b/hendrics/tests/test_a_complete_run.py @@ -7,11 +7,19 @@ import numpy as np import pytest -import hendrics as hen from astropy import log from astropy.io.registry import IORegistryError from hendrics import ( + base, + calibrate, + colors, + fspec, io, + lcurve, + plot, + power_colors, + read_events, + varenergy, ) from hendrics.io import HAS_H5PY from hendrics.tests import _dummy_par @@ -23,7 +31,7 @@ except NameError: FileNotFoundError = IOError -HEN_FILE_EXTENSION = hen.io.HEN_FILE_EXTENSION +HEN_FILE_EXTENSION = io.HEN_FILE_EXTENSION log.setLevel("DEBUG") # log.basicConfig(filename='HEN.log', level=log.DEBUG, filemode='w') @@ -63,7 +71,7 @@ def setup_class(cls): os.path.join(cls.datadir, "monol_testB.evt"), ) command = f"{data_a} {data_b} --discard-calibration" - hen.read_events.main(command.split()) + read_events.main(command.split()) data_a, data_b, rmf = ( os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), @@ -71,7 +79,7 @@ def setup_class(cls): os.path.join(cls.datadir, "test.rmf"), ) command = f"{data_a} {data_b} -r {rmf}" - hen.calibrate.main(command.split()) + calibrate.main(command.split()) cls.lcA = os.path.join( os.path.join(cls.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) ) @@ -81,21 +89,21 @@ def setup_class(cls): command = ( f"{cls.ev_fileAcal} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " f"-o {cls.lcA}" ) - hen.lcurve.main(command.split()) + lcurve.main(command.split()) command = ( f"{cls.ev_fileBcal} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " f"-o {cls.lcB}" ) - hen.lcurve.main(command.split()) + lcurve.main(command.split()) cls.pdsA = os.path.join(cls.datadir, "monol_testA_E3-50_pds" + HEN_FILE_EXTENSION) cls.pdsB = os.path.join(cls.datadir, "monol_testB_E3-50_pds" + HEN_FILE_EXTENSION) cls.cpds = os.path.join(cls.datadir, "monol_test_E3-50_cpds" + HEN_FILE_EXTENSION) command = f"{cls.lcA} {cls.lcB} -f 128 -k PDS --save-all --norm leahy" - hen.fspec.main(command.split()) + fspec.main(command.split()) command = f"{cls.lcA} {cls.lcB} -f 128 -k CPDS --save-all --norm leahy" - hen.fspec.main(command.split()) + fspec.main(command.split()) assert os.path.exists(cls.cpds) assert os.path.exists(cls.pdsA) assert os.path.exists(cls.pdsB) @@ -116,7 +124,7 @@ def test_get_file_type(self): } for realtype in file_list.keys(): fname = os.path.join(self.datadir, file_list[realtype] + HEN_FILE_EXTENSION) - ftype, _ = hen.io.get_file_type(fname) + ftype, _ = io.get_file_type(fname) assert ftype == realtype, "File types do not match" @pytest.mark.parametrize("format", ["qdp", "ecsv", "csv", "hdf5"]) @@ -127,7 +135,7 @@ def test_save_varen(self, kind, format): return try: - hen.varenergy.main( + varenergy.main( [ fname, "-f", @@ -149,22 +157,22 @@ def test_save_varen(self, kind, format): "nice", ] ) - out = hen.base.hen_root(fname) + f"_nice_{kind}" + f".{format}" + out = base.hen_root(fname) + f"_nice_{kind}" + f".{format}" assert os.path.exists(out) except IORegistryError: pass def test_colors_fail_uncalibrated(self): """Test light curve using PI filtering.""" - command = f"{self.ev_fileA} -b 100 -e {3} {5} {5} {10}" + command = f"{self.ev_fileA} -b 100 -e 3 5 5 10" with pytest.raises(ValueError, match="Energy information not found in file"): - hen.colors.main(command.split()) + colors.main(command.split()) def test_colors(self): """Test light curve using PI filtering.""" # calculate colors - command = f"{self.ev_fileAcal} -b 100 -e {3} {5} {5} {10}" - hen.colors.main(command.split()) + command = f"{self.ev_fileAcal} -b 100 -e 3 5 5 10" + colors.main(command.split()) new_filename = os.path.join( self.datadir, @@ -172,8 +180,8 @@ def test_colors(self): ) assert os.path.exists(new_filename) - out_lc = hen.io.load_lcurve(new_filename) - gti_to_test = hen.io.load_events(self.ev_fileA).gti + out_lc = io.load_lcurve(new_filename) + gti_to_test = io.load_events(self.ev_fileA).gti assert np.allclose(gti_to_test, out_lc.gti) def test_power_colors(self): @@ -184,10 +192,10 @@ def test_power_colors(self): UserWarning, match="(Some .non-log. power colors)|(All power spectral)|(Poisson-subtracted power)", ): - new_filenames = hen.power_colors.main(command.split()) + new_filenames = power_colors.main(command.split()) assert os.path.exists(new_filenames[0]) - hen.plot.main(new_filenames) + plot.main(new_filenames) def test_power_colors_2files(self): """Test light curve using PI filtering.""" @@ -197,24 +205,24 @@ def test_power_colors_2files(self): UserWarning, match="(Some .non-log.)|(All power spectral)|(Poisson-subtracted)|(cast to real)", ): - new_filenames = hen.power_colors.main(command.split()) + new_filenames = power_colors.main(command.split()) assert os.path.exists(new_filenames[0]) - hen.plot.main(new_filenames) + plot.main(new_filenames) def test_power_colors_2files_raises_no_cross_output(self): """Test light curve using PI filtering.""" # calculate colors with pytest.raises(ValueError, match="Specify --output only when processing"): command = f"{self.ev_fileAcal} {self.ev_fileBcal} -s 16 -b -6 -f 1 2 4 8 16 -o bubu.nc" - hen.power_colors.main(command.split()) + power_colors.main(command.split()) def test_readfile_fits(self): """Test reading and dumping a FITS file.""" fitsname = os.path.join(self.datadir, "monol_testA.evt") command = f"{fitsname}" - hen.io.main(command.split()) + io.main(command.split()) def test_plot_color(self): """Test plotting with linear axes.""" @@ -226,7 +234,7 @@ def test_plot_color(self): os.path.join(self.datadir, "monol_testA_nustar_fpma_E_10-5_over_5-3") + HEN_FILE_EXTENSION ) - hen.plot.main( + plot.main( [ cname, lname, @@ -248,14 +256,24 @@ def test_plot_hid(self): ) command = f"{data} -b 100 --energy-interval 3 10" - hen.lcurve.main(command.split()) + lcurve.main(command.split()) + import glob + + print( + glob.glob( + os.path.join( + self.datadir, + "*" + HEN_FILE_EXTENSION, + ) + ) + ) lname = os.path.join(self.datadir, "monol_testA_nustar_fpma_E3-10_lc") + HEN_FILE_EXTENSION - os.path.exists(lname) + assert os.path.exists(lname) cname = ( os.path.join(self.datadir, "monol_testA_nustar_fpma_E_10-5_over_5-3") + HEN_FILE_EXTENSION ) - hen.plot.main( + plot.main( [ cname, lname, diff --git a/hendrics/tests/test_base.py b/hendrics/tests/test_base.py index 6cc0b1b4..6449deff 100644 --- a/hendrics/tests/test_base.py +++ b/hendrics/tests/test_base.py @@ -4,7 +4,7 @@ import pytest from stingray.events import EventList -from hendrics.base import deorbit_events, normalize_dyn_profile +from hendrics.base import deorbit_events, normalize_dyn_profile, HAS_PINT from hendrics.tests import _dummy_par diff --git a/hendrics/tests/test_binary.py b/hendrics/tests/test_binary.py index cb69deb5..749115d8 100644 --- a/hendrics/tests/test_binary.py +++ b/hendrics/tests/test_binary.py @@ -5,12 +5,13 @@ import pytest -import hendrics as hen from hendrics.tests import _dummy_par +from hendrics import binary, io, calibrate, lcurve, read_events +from hendrics.base import HAS_PINT from . import cleanup_test_dir -HEN_FILE_EXTENSION = hen.io.HEN_FILE_EXTENSION +HEN_FILE_EXTENSION = io.HEN_FILE_EXTENSION try: FileNotFoundError @@ -45,14 +46,14 @@ def setup_class(cls): cls.par = _dummy_par("bubububu.par") data = os.path.join(cls.datadir, "monol_testA.evt") command = f"{data} --discard-calibration" - hen.read_events.main(command.split()) + read_events.main(command.split()) data, rmf = ( os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "test.rmf"), ) command = f"{data} -r {rmf}" - hen.calibrate.main(command.split()) + calibrate.main(command.split()) cls.lcA = os.path.join( os.path.join(cls.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) @@ -60,24 +61,24 @@ def setup_class(cls): command = ( f"{cls.ev_fileAcal} -e 3 50 --safe-interval 100 300 --nproc 2 -b 0.5 " f"-o {cls.lcA}" ) - hen.lcurve.main(command.split()) + lcurve.main(command.split()) def test_save_binary_events(self): f = self.ev_fileA with pytest.raises(ValueError, match="Energy filtering requested"): - hen.binary.main_presto(f"{f} -b 0.1 -e 3 59 --debug".split()) + binary.main_presto(f"{f} -b 0.1 -e 3 59 --debug".split()) @pytest.mark.remote_data @pytest.mark.skipif("not HAS_PINT") def test_save_binary_calibrated_events(self): f = self.ev_fileAcal - hen.binary.main_presto(f"{f} -b 0.1 -e 3 59 --debug --deorbit-par {self.par}".split()) + binary.main_presto(f"{f} -b 0.1 -e 3 59 --debug --deorbit-par {self.par}".split()) assert os.path.exists(f.replace(HEN_FILE_EXTENSION, ".dat")) assert os.path.exists(f.replace(HEN_FILE_EXTENSION, ".inf")) def test_save_binary_lc(self): f = self.lcA - hen.binary.main_presto(f"{f}".split()) + binary.main_presto(f"{f}".split()) assert os.path.exists(f.replace(HEN_FILE_EXTENSION, ".dat")) assert os.path.exists(f.replace(HEN_FILE_EXTENSION, ".inf")) diff --git a/hendrics/tests/test_calibrate.py b/hendrics/tests/test_calibrate.py index cafa18a5..b318b58e 100644 --- a/hendrics/tests/test_calibrate.py +++ b/hendrics/tests/test_calibrate.py @@ -3,14 +3,14 @@ import numpy as np import pytest -import hendrics as hen from hendrics.calibrate import default_nustar_rmf from hendrics.io import load_events, save_events from hendrics.tests import _dummy_par +from hendrics import calibrate, io, read_events, fake from . import cleanup_test_dir -HEN_FILE_EXTENSION = hen.io.HEN_FILE_EXTENSION +HEN_FILE_EXTENSION = io.HEN_FILE_EXTENSION def test_default_nustar_rmf(caplog): @@ -50,7 +50,7 @@ def setup_class(cls): os.path.join(cls.datadir, "monol_testB.evt"), ) command = f"{data_a} {data_b} ".format() - hen.read_events.main(command.split()) + read_events.main(command.split()) data_a, data_b, rmf = ( os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), @@ -58,12 +58,12 @@ def setup_class(cls): cls.rmf, ) command = f"{data_a} {data_b} -r {rmf} --nproc 2" - hen.calibrate.main(command.split()) + calibrate.main(command.split()) cls.xmm_fits_file = os.path.join(cls.datadir, "monol_test_fake_lc_xmm.evt") # Note that I don't specify the instrument. This is because # I want the internal machinery to understand that this is # XMM and this has to be given EPIC-pn by default. - hen.fake.main( + fake.main( [ "--deadtime", "1e-4", @@ -78,7 +78,7 @@ def setup_class(cls): ] ) command = f"{cls.xmm_fits_file} --discard-calibration" - hen.read_events.main(command.split()) + read_events.main(command.split()) cls.xmm_ev_file = os.path.join( cls.datadir, "monol_test_fake_lc_xmm_xmm_epn_det01_ev" + HEN_FILE_EXTENSION, @@ -88,12 +88,12 @@ def test_calibrate(self): """Test event file calibration.""" from astropy.io.fits import Header - ev = hen.io.load_events(self.ev_fileAcal) + ev = io.load_events(self.ev_fileAcal) assert hasattr(ev, "header") Header.fromstring(ev.header) assert hasattr(ev, "gti") - gti_to_test = hen.io.load_events(self.ev_fileA).gti + gti_to_test = io.load_events(self.ev_fileA).gti assert np.allclose(gti_to_test, ev.gti) def test_calibrate_xmm_raises(self): @@ -102,7 +102,7 @@ def test_calibrate_xmm_raises(self): command = f"{self.xmm_ev_file} -r {self.rmf}" with pytest.raises(RuntimeError, match="Calibration for XMM should work"): - hen.calibrate.main(command.split()) + calibrate.main(command.split()) def test_calibrate_raises_missing_mission(self): """Test event file calibration.""" @@ -115,7 +115,7 @@ def test_calibrate_raises_missing_mission(self): command = f"{bubu_fname} --rough" with pytest.raises(ValueError): - hen.calibrate.main(command.split()) + calibrate.main(command.split()) os.unlink(bubu_fname) @classmethod diff --git a/hendrics/tests/test_colors.py b/hendrics/tests/test_colors.py index b098338f..6e80622d 100644 --- a/hendrics/tests/test_colors.py +++ b/hendrics/tests/test_colors.py @@ -6,7 +6,7 @@ import numpy as np import pytest -import hendrics as hen +from hendrics import colors, io, lcurve, plot, read_events, calibrate from astropy import log from hendrics.tests import _dummy_par @@ -17,7 +17,7 @@ except NameError: FileNotFoundError = IOError -HEN_FILE_EXTENSION = hen.io.HEN_FILE_EXTENSION +HEN_FILE_EXTENSION = io.HEN_FILE_EXTENSION log.setLevel("DEBUG") # log.basicConfig(filename='HEN.log', level=log.DEBUG, filemode='w') @@ -57,7 +57,7 @@ def setup_class(cls): os.path.join(cls.datadir, "monol_testB.evt"), ) command = f"{data_a} {data_b} --discard-calibration" - hen.read_events.main(command.split()) + read_events.main(command.split()) data_a, data_b, rmf = ( os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), @@ -65,17 +65,17 @@ def setup_class(cls): os.path.join(cls.datadir, "test.rmf"), ) command = f"{data_a} {data_b} -r {rmf}" - hen.calibrate.main(command.split()) + calibrate.main(command.split()) cls.lc3_10 = os.path.join( os.path.join(cls.datadir, "monol_testA_E3-10_lc" + HEN_FILE_EXTENSION) ) command = f"{cls.ev_fileAcal} -e 3 10 -b 100 " f"-o {cls.lc3_10}" - hen.lcurve.main(command.split()) + lcurve.main(command.split()) command = f"{cls.ev_fileAcal} -b 100 -e {3} {5} {5} {10}" - hen.colors.main(command.split()) + colors.main(command.split()) cls.colorfile = os.path.join( cls.datadir, @@ -87,21 +87,21 @@ def test_colors_correct_gti(self): # calculate colors assert os.path.exists(self.colorfile) - out_lc = hen.io.load_lcurve(self.colorfile) - gti_to_test = hen.io.load_events(self.ev_fileA).gti + out_lc = io.load_lcurve(self.colorfile) + gti_to_test = io.load_events(self.ev_fileA).gti assert np.allclose(gti_to_test, out_lc.gti) def test_colors_fail_uncalibrated(self): """Test light curve using PI filtering.""" command = f"{self.ev_fileA} -b 100 -e {3} {5} {5} {10}" with pytest.raises(ValueError, match="Energy information not found in file"): - hen.colors.main(command.split()) + colors.main(command.split()) def test_plot_color(self): """Test plotting with linear axes.""" lname = self.colorfile cname = self.colorfile - hen.plot.main( + plot.main( [ cname, lname, @@ -118,11 +118,11 @@ def test_plot_hid(self): """Test plotting with linear axes.""" # also produce a light curve with the same binning command = f"{self.ev_fileAcal} -b 100 --energy-interval {3} {10}" - hen.lcurve.main(command.split()) + lcurve.main(command.split()) lname = self.lc3_10 cname = self.colorfile - hen.plot.main( + plot.main( [ cname, lname, diff --git a/hendrics/tests/test_efsearch.py b/hendrics/tests/test_efsearch.py index 4618e264..d8b06c4a 100644 --- a/hendrics/tests/test_efsearch.py +++ b/hendrics/tests/test_efsearch.py @@ -8,10 +8,11 @@ from stingray.events import EventList from stingray.lightcurve import Lightcurve -from hendrics.base import hen_root +from hendrics.base import hen_root, HAS_PINT from hendrics.efsearch import ( decide_binary_parameters, folding_orbital_search, + HAS_IMAGEIO, main_accelsearch, main_efsearch, main_z2vspf, diff --git a/hendrics/tests/test_fake.py b/hendrics/tests/test_fake.py index e33ffa17..60affdac 100644 --- a/hendrics/tests/test_fake.py +++ b/hendrics/tests/test_fake.py @@ -5,11 +5,14 @@ import numpy as np import pytest -from stingray.events import EventList +from stingray import EventList -import hendrics as hen from astropy import log from astropy.io import fits + +from hendrics import fake, io, read_events, calibrate, base +from hendrics.base import HAS_PINT + from hendrics.fake import scramble from hendrics.io import load_events from hendrics.tests import _dummy_par @@ -21,7 +24,7 @@ except NameError: FileNotFoundError = IOError -HEN_FILE_EXTENSION = hen.io.HEN_FILE_EXTENSION +HEN_FILE_EXTENSION = io.HEN_FILE_EXTENSION log.setLevel("DEBUG") # log.basicConfig(filename='HEN.log', level=log.DEBUG, filemode='w') @@ -30,7 +33,7 @@ def test_filter_for_deadtime_nonpar(): """Test dead time filter, non-paralyzable case.""" events = np.array([1, 1.05, 1.07, 1.08, 1.1, 2, 2.2, 3, 3.1, 3.2]) - filt_events = hen.fake.filter_for_deadtime(events, 0.11) + filt_events = fake.filter_for_deadtime(events, 0.11) expected = np.array([1, 2, 2.2, 3, 3.2]) assert np.all(filt_events == expected), f"Wrong: {filt_events} vs {expected}" @@ -39,7 +42,7 @@ def test_filter_for_deadtime_nonpar_bkg(): """Test dead time filter, non-paralyzable case, with background.""" events = np.array([1.1, 2, 2.2, 3, 3.2]) bkg_events = np.array([1, 3.1]) - filt_events, info = hen.fake.filter_for_deadtime( + filt_events, info = fake.filter_for_deadtime( events, 0.11, bkg_ev_list=bkg_events, return_all=True ) expected_ev = np.array([2, 2.2, 3, 3.2]) @@ -52,7 +55,7 @@ def test_filter_for_deadtime_par(): """Test dead time filter, paralyzable case.""" events = np.array([1, 1.1, 2, 2.2, 3, 3.1, 3.2]) assert np.all( - hen.fake.filter_for_deadtime(events, 0.11, paralyzable=True) == np.array([1, 2, 2.2, 3]) + fake.filter_for_deadtime(events, 0.11, paralyzable=True) == np.array([1, 2, 2.2, 3]) ) @@ -60,7 +63,7 @@ def test_filter_for_deadtime_par_bkg(): """Test dead time filter, paralyzable case, with background.""" events = np.array([1.1, 2, 2.2, 3, 3.2]) bkg_events = np.array([1, 3.1]) - filt_events, info = hen.fake.filter_for_deadtime( + filt_events, info = fake.filter_for_deadtime( events, 0.11, bkg_ev_list=bkg_events, @@ -80,7 +83,7 @@ def test_filter_for_deadtime_par_bkg_obj(): energies = np.arange(times.size) + 10 events = EventList(time=times, energy=energies, pi=pis) bkg_events = np.array([1, 3.1]) - filt_events, info = hen.fake.filter_for_deadtime( + filt_events, info = fake.filter_for_deadtime( events, 0.11, bkg_ev_list=bkg_events, @@ -105,7 +108,7 @@ def test_deadtime_mask_par(): """Test dead time filter, paralyzable case, with background.""" events = np.array([1.1, 2, 2.2, 3, 3.2]) bkg_events = np.array([1, 3.1]) - filt_events, info = hen.fake.filter_for_deadtime( + filt_events, info = fake.filter_for_deadtime( events, 0.11, bkg_ev_list=bkg_events, @@ -120,8 +123,8 @@ def test_deadtime_conversion(): """Test the functions for count rate conversion.""" original_rate = np.arange(1, 1000, 10) deadtime = 2.5e-3 - rdet = hen.base.r_det(deadtime, original_rate) - inner_radius = hen.base.r_in(deadtime, rdet) + rdet = base.r_det(deadtime, original_rate) + inner_radius = base.r_in(deadtime, rdet) np.testing.assert_almost_equal(inner_radius, original_rate) @@ -153,16 +156,16 @@ def setup_class(cls): cls.par = _dummy_par("bubububu.par") cls.fits_fileA = os.path.join(cls.datadir, "monol_testA.evt") command = f"{cls.fits_fileA} --discard-calibration" - hen.read_events.main(command.split()) + read_events.main(command.split()) cls.first_event_file_cal = "calibrated" + HEN_FILE_EXTENSION - hen.calibrate.calibrate(cls.first_event_file, cls.first_event_file_cal, rough=True) + calibrate.calibrate(cls.first_event_file, cls.first_event_file_cal, rough=True) cls.xmm_fits_file = os.path.join(cls.datadir, "monol_test_fake_lc_xmm.evt") # Note that I don't specify the instrument. This is because # I want the internal machinery to understand that this is # XMM and this has to be given EPIC-pn by default. - hen.fake.main( + fake.main( [ "--deadtime", "1e-4", @@ -177,7 +180,7 @@ def setup_class(cls): ] ) command = f"{cls.xmm_fits_file} --discard-calibration" - hen.read_events.main(command.split()) + read_events.main(command.split()) cls.xmm_ev_file = os.path.join( cls.datadir, "monol_test_fake_lc_xmm_xmm_epn_det01_ev" + HEN_FILE_EXTENSION, @@ -190,9 +193,9 @@ def test_checksums(self): def test_fake_file(self): """Test produce a fake event file.""" fits_file = os.path.join(self.datadir, "monol_test_fake.evt") - hen.fake.main(["-o", fits_file, "--instrument", "FPMB"]) + fake.main(["-o", fits_file, "--instrument", "FPMB"]) verify_all_checksums(fits_file) - info = hen.io.print_fits_info(fits_file, hdu=1) + info = io.print_fits_info(fits_file, hdu=1) assert info["Instrument"] == "FPMB" def test_fake_file_from_input_lc(self): @@ -200,14 +203,14 @@ def test_fake_file_from_input_lc(self): lcurve_in = os.path.join(self.datadir, "lcurveA.fits") fits_file = os.path.join(self.datadir, "monol_test_fake_lc.evt") with pytest.warns(UserWarning, match="FITS light curve handling is st"): - hen.fake.main(["--lc", lcurve_in, "-o", fits_file]) + fake.main(["--lc", lcurve_in, "-o", fits_file]) verify_all_checksums(fits_file) def test_fake_file_with_deadtime(self): """Test produce a fake event file and apply deadtime.""" fits_file = os.path.join(self.datadir, "monol_test_fake_lc.evt") - hen.fake.main(["--deadtime", "2.5e-3", "--ctrate", "2000", "-o", fits_file]) + fake.main(["--deadtime", "2.5e-3", "--ctrate", "2000", "-o", fits_file]) verify_all_checksums(fits_file) def test_fake_file_xmm(self): @@ -225,17 +228,17 @@ def test_fake_file_xmm(self): def test_load_events_randomize(self): """Test event file reading.""" - newfiles = hen.read_events.treat_event_file(self.fits_fileA, randomize_by=0.073) + newfiles = read_events.treat_event_file(self.fits_fileA, randomize_by=0.073) clean_file = self.first_event_file - ev_clean = hen.io.load_events(clean_file) - ev = hen.io.load_events(newfiles[0]) + ev_clean = io.load_events(clean_file) + ev = io.load_events(newfiles[0]) diff = ev.time - ev_clean.time assert np.all(np.abs(diff) <= 0.073 / 2) assert np.all(np.abs(diff) > 0.0) def test_scramble_events_file(self): command = f"{self.first_event_file}" - newfile = hen.fake.main_scramble(command.split()) + newfile = fake.main_scramble(command.split()) assert os.path.exists(newfile) os.remove(newfile) @@ -244,13 +247,13 @@ def test_fake_fits_input_events_file(self, fname): newfile = "bububuasdf.fits" infname = getattr(self, fname) command = f"-e {infname} -o {newfile}" - _ = hen.fake.main(command.split()) + _ = fake.main(command.split()) assert os.path.exists(newfile) verify_all_checksums(newfile) events0 = load_events(infname) - newf = hen.read_events.treat_event_file(newfile) + newf = read_events.treat_event_file(newfile) events1 = load_events(newf[0]) @@ -271,11 +274,11 @@ def test_scramble_uncalibrated_events_file_raises(self): command = f"{self.first_event_file} -e 3 30" with pytest.raises(ValueError): with pytest.warns(UserWarning, match="No energy information"): - _ = hen.fake.main_scramble(command.split()) + _ = fake.main_scramble(command.split()) def test_scramble_calibrated_events_file(self): command = f"{self.first_event_file_cal} -e 3 30" - newfile = hen.fake.main_scramble(command.split()) + newfile = fake.main_scramble(command.split()) assert "3-30" in newfile assert os.path.exists(newfile) os.remove(newfile) @@ -285,7 +288,7 @@ def test_scramble_calibrated_events_file(self): def test_scramble_events_file_deorbit(self): _ = _dummy_par("bububububu.par", pb=1.0, a1=30) command = f"{self.first_event_file} --deorbit-par bububububu.par" - newfile = hen.fake.main_scramble(command.split()) + newfile = fake.main_scramble(command.split()) assert os.path.exists(newfile) os.remove(newfile) @@ -312,13 +315,13 @@ def test_calibrate_xmm(self): rmf = os.path.join(self.datadir, "test.rmf") command = f"{xmm_file} -r {rmf} --nproc 2" with pytest.raises(RuntimeError): - hen.calibrate.main(command.split()) + calibrate.main(command.split()) def test_calibrate_xmm_normf(self): """Test event file calibration.""" xmm_file = self.xmm_ev_file command = f"{xmm_file} --rough --nproc 2" - hen.calibrate.main(command.split()) + calibrate.main(command.split()) @classmethod def teardown_class(cls): diff --git a/hendrics/tests/test_fspec.py b/hendrics/tests/test_fspec.py index 967f1175..8fbf2492 100644 --- a/hendrics/tests/test_fspec.py +++ b/hendrics/tests/test_fspec.py @@ -11,12 +11,21 @@ import pytest import stingray -from stingray.events import EventList +from stingray import EventList -import hendrics as hen from astropy import log from hendrics import ( + base, io, + fspec, + lcurve, + modeling, + plot, + read_events, + rebin, + save_as_xspec, + sum_fspec, + timelags, ) from hendrics.base import HENDRICS_STAR_VALUE, touch from hendrics.fspec import calc_cpds, calc_pds @@ -29,7 +38,7 @@ except NameError: FileNotFoundError = IOError -HEN_FILE_EXTENSION = hen.io.HEN_FILE_EXTENSION +HEN_FILE_EXTENSION = io.HEN_FILE_EXTENSION log.setLevel("DEBUG") # log.basicConfig(filename='HEN.log', level=log.DEBUG, filemode='w') @@ -66,8 +75,8 @@ def test_distributed_pds(): dt=0.1, norm="leahy", ) - pds_iterable = hen.fspec._provide_periodograms(events, 100, 0.1, "leahy") - pds_distr = hen.fspec.average_periodograms(pds_iterable) + pds_iterable = fspec._provide_periodograms(events, 100, 0.1, "leahy") + pds_distr = fspec.average_periodograms(pds_iterable) assert np.allclose(pds_distr.power, single_periodogram.power) assert np.allclose(pds_distr.freq, single_periodogram.freq) assert pds_distr.m == single_periodogram.m @@ -90,8 +99,8 @@ def test_distributed_cpds(): events1, events2, segment_size=100, dt=0.1, norm="leahy" ) - pds_iterable = hen.fspec._provide_cross_periodograms(events1, events2, 100, 0.1, "leahy") - pds_distr = hen.fspec.average_periodograms(pds_iterable) + pds_iterable = fspec._provide_cross_periodograms(events1, events2, 100, 0.1, "leahy") + pds_distr = fspec.average_periodograms(pds_iterable) assert np.allclose(pds_distr.power, single_periodogram.power) assert np.allclose(pds_distr.freq, single_periodogram.freq) assert pds_distr.m == single_periodogram.m @@ -127,10 +136,10 @@ def setup_class(cls): os.path.join(cls.datadir, "monol_testB.evt"), ) command = f"{data_a} {data_b}" - hen.read_events.main(command.split()) + read_events.main(command.split()) command = f"{cls.ev_fileA} {cls.ev_fileB} --nproc 2 -b -1" - hen.lcurve.main(command.split()) + lcurve.main(command.split()) cls.lcA = cls.ev_fileA.replace("_ev", "_lc") cls.lcB = cls.ev_fileB.replace("_ev", "_lc") @@ -148,10 +157,10 @@ def setup_class(cls): ) command = f"{cls.ev_fileA} {cls.ev_fileB} -f 128 -k PDS --save-all --norm leahy --emin 3 --emax 50" - hen.fspec.main(command.split()) + fspec.main(command.split()) command = f"{cls.ev_fileA} {cls.ev_fileB} -f 128 -k CPDS --save-all --norm leahy --emin 3 --emax 50" - hen.fspec.main(command.split()) + fspec.main(command.split()) for pds in [pdsA, pdsB, cpds]: assert os.path.exists(pds) @@ -161,7 +170,7 @@ def test_pds_leahy_emax_only(self): evdata = self.ev_fileA command = f"{evdata} -f 128 -k PDS --save-all --norm leahy -b {1} --emax 50" - hen.fspec.main(command.split()) + fspec.main(command.split()) out = os.path.join( self.datadir, @@ -175,7 +184,7 @@ def test_pds_leahy_emin_only(self): evdata = self.ev_fileA command = f"{evdata} -f 128 -k PDS --save-all --norm leahy -b {1} --emin 3" - hen.fspec.main(command.split()) + fspec.main(command.split()) out = os.path.join( self.datadir, @@ -190,17 +199,17 @@ def test_pds_leahy(self): lcdata = self.lcA command = f"{evdata} -f 128. -k PDS --norm leahy -b -1" - hen.fspec.main(command.split()) + fspec.main(command.split()) evout = evdata.replace("_ev", "_pds") assert os.path.exists(evout) - evpds = hen.io.load_pds(evout) + evpds = io.load_pds(evout) io.remove_pds(evout) command = f"{lcdata} -f 128. -k PDS --save-all --norm leahy" - hen.fspec.main(command.split()) + fspec.main(command.split()) lcout = lcdata.replace("_lc", "_pds") assert os.path.exists(lcout) - lcpds = hen.io.load_pds(lcout) + lcpds = io.load_pds(lcout) io.remove_pds(lcout) assert np.allclose(evpds.power, lcpds.power) @@ -211,17 +220,17 @@ def test_pds_leahy_lombscargle(self): lcdata = self.lcA command = f"{evdata} -k PDS --norm leahy --lombscargle -b -1" - hen.fspec.main(command.split()) + fspec.main(command.split()) evout = evdata.replace("_ev", "_LS_pds") assert os.path.exists(evout) - evpds = hen.io.load_pds(evout) + evpds = io.load_pds(evout) io.remove_pds(evout) command = f"{lcdata} -k PDS --norm leahy --lombscargle" - hen.fspec.main(command.split()) + fspec.main(command.split()) lcout = lcdata.replace("_lc", "_LS_pds") assert os.path.exists(lcout) - lcpds = hen.io.load_pds(lcout) + lcpds = io.load_pds(lcout) io.remove_pds(lcout) assert np.allclose(evpds.power, lcpds.power) @@ -232,10 +241,10 @@ def test_cpds_leahy_lombscargle(self): evdata2 = self.ev_fileB command = f"{evdata1} {evdata2} -k CPDS --norm leahy --lombscargle -b -1" - hen.fspec.main(command.split()) + fspec.main(command.split()) evout = evdata1.replace("fpma", "fpm").replace("testA", "test").replace("_ev", "_LS_cpds") assert os.path.exists(evout) - evpds = hen.io.load_pds(evout) + evpds = io.load_pds(evout) io.remove_pds(evout) def test_pds_save_nothing(self): @@ -245,16 +254,16 @@ def test_pds_save_nothing(self): lcout = lcdata.replace("_lc", "_pds") command = f"{evdata} -f 128 -k PDS --norm leahy --no-auxil -b 0.5" - hen.fspec.main(command.split()) + fspec.main(command.split()) assert os.path.exists(evout) - evpds = hen.io.load_pds(evout) + evpds = io.load_pds(evout) assert not os.path.exists(evout.replace(HEN_FILE_EXTENSION, "")) io.remove_pds(evout) command = f"{lcdata} -f 128 -k PDS --norm leahy --no-auxil " - hen.fspec.main(command.split()) + fspec.main(command.split()) assert os.path.exists(lcout) - lcpds = hen.io.load_pds(lcout) + lcpds = io.load_pds(lcout) assert not os.path.exists(evout.replace(HEN_FILE_EXTENSION, "")) io.remove_pds(lcout) @@ -288,13 +297,13 @@ def test_pds(self, data_kind, lombscargle): os.path.join(self.datadir, f"monol_testB_nustar_fpmb{label}") + HEN_FILE_EXTENSION, ) command = f"{opts} {data_a} {data_b}" - hen.fspec.main(command.split()) + fspec.main(command.split()) assert os.path.exists(outA) assert os.path.exists(outB) - new_pdsA = hen.io.load_pds(outA) - new_pdsB = hen.io.load_pds(outB) + new_pdsA = io.load_pds(outA) + new_pdsB = io.load_pds(outB) for pds in [new_pdsA, new_pdsB]: if not lombscargle: assert hasattr(pds, "cs_all") @@ -319,7 +328,7 @@ def test_ignore_gti(self, data_kind): os.path.join(self.datadir, f"monol_testB_nustar_fpmb{label}") + HEN_FILE_EXTENSION, ) command = f"{data_a} {data_b} -f 128 --ignore-gtis" - hen.fspec.main(command.split()) + fspec.main(command.split()) outA = os.path.join(self.datadir, "monol_testA_nustar_fpma_pds" + HEN_FILE_EXTENSION) outB = os.path.join(self.datadir, "monol_testB_nustar_fpmb_pds" + HEN_FILE_EXTENSION) @@ -338,7 +347,7 @@ def test_pds_events_big(self, kind): os.path.join(self.datadir, f"monol_testB_{labelB}") + HEN_FILE_EXTENSION, ) command = f"{data_a} {data_b} -f 16 -k {kind} --norm frac --test" - hen.fspec.main(command.split()) + fspec.main(command.split()) def test_cpds_ignore_instr(self): """Test CPDS production.""" @@ -348,28 +357,28 @@ def test_cpds_ignore_instr(self): f" -o {out} --debug" ) - hen.fspec.main(command.split()) + fspec.main(command.split()) def test_cpds_rms_norm(self): """Test CPDS production.""" out = os.path.join(self.datadir, "monol_test_3-50keV_rms") command = f"{self.lcA} {self.lcB} -f 128 --save-dyn -k CPDS --save-all --norm rms -o {out}" - hen.fspec.main(command.split()) + fspec.main(command.split()) def test_cpds_wrong_norm(self): """Test CPDS production.""" out = os.path.join(self.datadir, "monol_test_3-50keV_wrong") command = f"{self.lcA} {self.lcB} -f 128 --save-dyn -k CPDS --norm blablabla -o {out}" with pytest.warns(UserWarning, match="Beware! Unknown normalization"): - hen.fspec.main(command.split()) + fspec.main(command.split()) def test_cpds_dtbig(self): """Test CPDS production.""" out = os.path.join(self.datadir, "monol_test_3-50keV_dtb") command = f"{self.lcA} {self.lcB} -f 128 --save-dyn -k CPDS --save-all --norm frac -o {out}" command += " -b 1" - hen.fspec.main(command.split()) + fspec.main(command.split()) def test_dumpdynpds(self): """Test dump dynamical PDSs.""" @@ -379,11 +388,11 @@ def test_dumpdynpds(self): + HEN_FILE_EXTENSION ) with pytest.raises(NotImplementedError): - hen.fspec.dumpdyn_main(command.split()) + fspec.dumpdyn_main(command.split()) def test_sumpds(self): """Test the sum of pdss.""" - hen.sum_fspec.main( + sum_fspec.main( [ os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds") + HEN_FILE_EXTENSION, @@ -400,7 +409,7 @@ def test_dumpdyncpds(self): "--noplot " + os.path.join(self.datadir, "monol_test_3-50keV_cpds") + HEN_FILE_EXTENSION ) with pytest.raises(NotImplementedError): - hen.fspec.dumpdyn_main(command.split()) + fspec.dumpdyn_main(command.split()) def test_rebinpds(self): """Test PDS rebinning 1.""" @@ -408,7 +417,7 @@ def test_rebinpds(self): os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds") + HEN_FILE_EXTENSION ) command = f"{data} -r 2" - hen.rebin.main(command.split()) + rebin.main(command.split()) os.path.exists( os.path.join( self.datadir, @@ -423,7 +432,7 @@ def test_rebinpds_geom(self): os.path.join(self.datadir, "monol_testB_nustar_fpmb_3-50keV_pds") + HEN_FILE_EXTENSION, ) command = f"{data_a} {data_b} -r 1.03" - hen.rebin.main(command.split()) + rebin.main(command.split()) os.path.exists( os.path.join( self.datadir, @@ -441,8 +450,8 @@ def test_rebincpds(self): """Test CPDS rebinning.""" data = os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") + HEN_FILE_EXTENSION command = f"{data} -r 2" - hen.rebin.main(command.split()) - os.path.exists( + rebin.main(command.split()) + assert os.path.exists( os.path.join( self.datadir, "monol_test_nustar_fpm_3-50keV_cpds_rebin2" + HEN_FILE_EXTENSION, @@ -453,7 +462,7 @@ def test_rebincpds_geom(self): """Test CPDS geometrical rebinning.""" data = os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds") + HEN_FILE_EXTENSION command = f"{data} -r 1.03" - hen.rebin.main(command.split()) + rebin.main(command.split()) os.path.exists( os.path.join( self.datadir, @@ -466,8 +475,8 @@ def test_save_lags(self): self.datadir, "monol_test_nustar_fpm_3-50keV_cpds_rebin2" + HEN_FILE_EXTENSION, ) - hen.timelags.main([fname]) - out = hen.base.hen_root(fname) + "_lags.qdp" + timelags.main([fname]) + out = base.hen_root(fname) + "_lags.qdp" os.path.exists(out) def test_fit_pds(self): @@ -488,13 +497,13 @@ def test_fit_pds(self): ) command = f"{pdsfile1} {pdsfile2} -m {modelfile} --frequency-interval 0 10" - hen.modeling.main_model(command.split()) + modeling.main_model(command.split()) out0 = os.path.join(self.datadir, "monol_testA_nustar_fpma_3-50keV_pds_bestfit.p") out1 = os.path.join(self.datadir, "monol_testB_nustar_fpmb_3-50keV_pds_bestfit.p") assert os.path.exists(out0) assert os.path.exists(out1) - m, k, c = hen.io.load_model( + m, k, c = io.load_model( os.path.join(self.datadir, "monol_testB_nustar_fpmb_3-50keV_pds_bestfit.p") ) assert hasattr(m, "amplitude") @@ -511,7 +520,7 @@ def test_fit_pds(self): ) assert os.path.exists(out0) assert os.path.exists(out1) - spec = hen.io.load_pds(out0) + spec = io.load_pds(out0) assert hasattr(spec, "best_fits") def test_fit_cpds(self): @@ -530,11 +539,11 @@ def test_fit_cpds(self): command = f"{pdsfile1} -m {modelfile} --frequency-interval 0 10" with pytest.warns(ComplexWarning): - hen.modeling.main_model(command.split()) + modeling.main_model(command.split()) out0 = os.path.join(self.datadir, "monol_test_nustar_fpm_3-50keV_cpds_bestfit.p") assert os.path.exists(out0) - m, k, c = hen.io.load_model(out0) + m, k, c = io.load_model(out0) assert hasattr(m, "amplitude") os.unlink(out0) @@ -543,7 +552,7 @@ def test_fit_cpds(self): "monol_test_nustar_fpm_3-50keV_cpds_fit" + HEN_FILE_EXTENSION, ) assert os.path.exists(out0) - spec = hen.io.load_pds(out0) + spec = io.load_pds(out0) assert hasattr(spec, "best_fits") def test_fit_pds_f_no_of_intervals_invalid(self): @@ -565,7 +574,7 @@ def test_fit_pds_f_no_of_intervals_invalid(self): command = f"{pdsfile1} {pdsfile2} -m {modelfile} --frequency-interval 0 1 9" with pytest.raises(ValueError, match="Invalid number of frequencies specified"): - hen.modeling.main_model(command.split()) + modeling.main_model(command.split()) def test_savexspec(self): """Test save as Xspec 1.""" @@ -574,7 +583,7 @@ def test_savexspec(self): + HEN_FILE_EXTENSION ) command = f"{data}" - hen.save_as_xspec.main(command.split()) + save_as_xspec.main(command.split()) os.path.exists(os.path.join(self.datadir, "monol_testA_nustar_fpmb_3-50keV_pds_rebin2.pha")) def test_savexspec_geom(self): @@ -585,7 +594,7 @@ def test_savexspec_geom(self): ) command = f"{data}" - hen.save_as_xspec.main(command.split()) + save_as_xspec.main(command.split()) os.path.exists( os.path.join( @@ -611,7 +620,7 @@ def test_plot_lin(self): + HEN_FILE_EXTENSION ) lname = os.path.join(self.datadir, "monol_testA_nustar_fpma_lc") + HEN_FILE_EXTENSION - hen.plot.main( + plot.main( [ pname, cname, @@ -623,7 +632,7 @@ def test_plot_lin(self): "dummy.qdp", ] ) - hen.plot.main( + plot.main( [ lname, "--noplot", @@ -650,7 +659,7 @@ def test_plot_log(self): "monol_test_nustar_fpm_3-50keV_cpds_rebin1.03" + HEN_FILE_EXTENSION, ) - hen.plot.main( + plot.main( [ pname, cname, @@ -662,7 +671,7 @@ def test_plot_log(self): "dummy.qdp", ] ) - hen.plot.main( + plot.main( [ pname, "--noplot", @@ -682,7 +691,7 @@ def test_plot_save_figure(self): self.datadir, "monol_testA_nustar_fpma_3-50keV_pds_rebin1.03" + HEN_FILE_EXTENSION, ) - hen.plot.main( + plot.main( [ pname, "--noplot", diff --git a/hendrics/tests/test_gti.py b/hendrics/tests/test_gti.py index b3f635ba..3de66403 100644 --- a/hendrics/tests/test_gti.py +++ b/hendrics/tests/test_gti.py @@ -3,10 +3,9 @@ import os -import hendrics as hen from astropy import log from hendrics.tests import _dummy_par - +from hendrics import io, create_gti, lcurve, read_events, calibrate from . import cleanup_test_dir try: @@ -14,7 +13,7 @@ except NameError: FileNotFoundError = IOError -HEN_FILE_EXTENSION = hen.io.HEN_FILE_EXTENSION +HEN_FILE_EXTENSION = io.HEN_FILE_EXTENSION log.setLevel("DEBUG") # log.basicConfig(filename='HEN.log', level=log.DEBUG, filemode='w') @@ -54,18 +53,18 @@ def setup_class(cls): os.path.join(cls.datadir, "monol_testB.evt"), ) command = f"{data_a} {data_b}" - hen.read_events.main(command.split()) + read_events.main(command.split()) command = f"{cls.ev_fileA} {cls.ev_fileB} -r {os.path.join(cls.datadir, 'test.rmf')}" - hen.calibrate.main(command.split()) + calibrate.main(command.split()) cls.lcA = os.path.join(os.path.join(cls.datadir, "monol_testA_lc" + HEN_FILE_EXTENSION)) cls.lcB = os.path.join(os.path.join(cls.datadir, "monol_testB_lc" + HEN_FILE_EXTENSION)) command = f"{cls.ev_fileAcal} --nproc 2 -b 2 " f"-o {cls.lcA}" - hen.lcurve.main(command.split()) + lcurve.main(command.split()) command = f"{cls.ev_fileBcal} --nproc 2 -b 2 " f"-o {cls.lcB}" - hen.lcurve.main(command.split()) + lcurve.main(command.split()) command = f"{cls.ev_fileA} -f time>0 -c --debug" - hen.create_gti.main(command.split()) + create_gti.main(command.split()) cls.gtifile = os.path.join(cls.datadir, "monol_testA_nustar_fpma_gti") + HEN_FILE_EXTENSION def test_create_gti(self): @@ -78,28 +77,28 @@ def test_apply_gti(self): lcfname = self.ev_fileA lcoutname = self.ev_fileA.replace(HEN_FILE_EXTENSION, "_gtifilt" + HEN_FILE_EXTENSION) command = f"{lcfname} -a {fname} --debug" - hen.create_gti.main(command.split()) - hen.io.load_events(lcoutname) + create_gti.main(command.split()) + io.load_events(lcoutname) def test_create_gti_and_minlen(self): """Test creating a GTI file and apply minimum length.""" fname = self.lcA command = f"{fname} -f counts>0 -c -l 10 --debug" - hen.create_gti.main(command.split()) + create_gti.main(command.split()) def test_create_gti_and_apply(self): """Test applying a GTI file and apply minimum length.""" fname = self.gtifile lcfname = self.lcA command = f"{lcfname} -a {fname} -l 10 --debug" - hen.create_gti.main(command.split()) + create_gti.main(command.split()) def test_readfile(self): """Test reading and dumping a HENDRICS file.""" fname = self.gtifile command = f"{fname}" - hen.io.main(command.split()) + io.main(command.split()) @classmethod def teardown_class(cls): diff --git a/hendrics/tests/test_io.py b/hendrics/tests/test_io.py index e2e1a163..8d903328 100644 --- a/hendrics/tests/test_io.py +++ b/hendrics/tests/test_io.py @@ -19,6 +19,7 @@ from hendrics.base import hen_root from hendrics.io import ( HAS_H5PY, + HAS_C256, HEN_FILE_EXTENSION, _split_high_precision_number, find_file_in_allowed_paths, diff --git a/hendrics/tests/test_lc.py b/hendrics/tests/test_lc.py index b35bedb4..a37883b5 100644 --- a/hendrics/tests/test_lc.py +++ b/hendrics/tests/test_lc.py @@ -7,7 +7,6 @@ import pytest from stingray.lightcurve import Lightcurve -import hendrics as hen from astropy import log from astropy.logger import AstropyUserWarning from hendrics.io import HEN_FILE_EXTENSION, get_file_type @@ -15,6 +14,19 @@ from hendrics.read_events import treat_event_file from hendrics.tests import _dummy_par +from hendrics import ( + base, + calibrate, + create_gti, + exvar, + fspec, + io, + plot, + rebin, + read_events, + lcurve, + exposure, +) from . import cleanup_test_dir try: @@ -58,7 +70,7 @@ def test_treat_event_file_nustar(self): def test_treat_event_file_nustar_energy(self): rmf = os.path.join(self.datadir, "test.rmf") command = f"{self.new_filename} -r {rmf} --nproc 2" - hen.calibrate.main(command.split()) + calibrate.main(command.split()) lcurve_from_events(self.calib_filename, e_interval=[3, 50]) newfile = os.path.join( @@ -110,14 +122,14 @@ def setup_class(cls): os.path.join(cls.datadir, "monol_testB.evt"), ) command = f"{data_a} {data_b} --discard-calibration" - hen.read_events.main(command.split()) + read_events.main(command.split()) data_a, data_b, rmf = ( os.path.join(cls.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "monol_testB_nustar_fpmb_ev" + HEN_FILE_EXTENSION), os.path.join(cls.datadir, "test.rmf"), ) command = f"{data_a} {data_b} -r {rmf}" - hen.calibrate.main(command.split()) + calibrate.main(command.split()) def test_lcurve(self): """Test light curve production.""" @@ -130,21 +142,21 @@ def test_lcurve(self): f"{self.ev_fileAcal} -e {3} {50} --safe-interval " f"{100} {300} --nproc 2 -b 0.5 -o {new_filename}" ) - hen.lcurve.main(command.split()) + lcurve.main(command.split()) assert os.path.exists(new_filename) - lc = hen.io.load_lcurve(new_filename) + lc = io.load_lcurve(new_filename) assert hasattr(lc, "header") # Test that the header is correctly conserved Header.fromstring(lc.header) assert hasattr(lc, "gti") - gti_to_test = hen.io.load_events(self.ev_fileAcal).gti + gti_to_test = io.load_events(self.ev_fileAcal).gti assert np.allclose(gti_to_test, lc.gti) def test_lcurve_B(self): out = os.path.join(self.datadir, "monol_testB_E3-50_lc" + HEN_FILE_EXTENSION) command = f"{self.ev_fileBcal} -e 3 50 --safe-interval 100 300 -b 0.5 -o {out}" - hen.lcurve.main(command.split()) + lcurve.main(command.split()) assert os.path.exists( os.path.join(self.datadir, "monol_testB_E3-50_lc" + HEN_FILE_EXTENSION) ) @@ -156,22 +168,22 @@ def test_weight_lcurve(self): new_lc = "polar_weightbla_lc" + HEN_FILE_EXTENSION new_ev = "polar_ev" + HEN_FILE_EXTENSION - events = hen.io.load_events(self.ev_fileAcal) + events = io.load_events(self.ev_fileAcal) events.bla = np.random.uniform(0, 1, events.time.size) - hen.io.save_events(events, new_ev) + io.save_events(events, new_ev) command = f"{new_ev} -b 10 --weight-on bla" - hen.lcurve.main(command.split()) + lcurve.main(command.split()) assert os.path.exists(new_lc) - lc = hen.io.load_lcurve(new_lc) + lc = io.load_lcurve(new_lc) assert hasattr(lc, "header") # Test that the header is correctly conserved Header.fromstring(lc.header) assert hasattr(lc, "gti") - gti_to_test = hen.io.load_events(new_ev).gti + gti_to_test = io.load_events(new_ev).gti assert np.allclose(gti_to_test, lc.gti) assert lc.err_dist == "gauss" @@ -183,19 +195,19 @@ def test_lcurve_noclobber(self): with pytest.warns(AstropyUserWarning, match="File exists, and noclobber"): command = f"{input_file} -o {new_filename} --noclobber" - hen.lcurve.main(command.split()) + lcurve.main(command.split()) def test_lcurve_split(self): """Test lc with gti-split option.""" command = f"{self.ev_fileAcal} {self.ev_fileBcal} -g" - hen.lcurve.main(command.split()) + lcurve.main(command.split()) new_filename = os.path.join( self.datadir, "monol_testA_nustar_fpma_gti000_lc" + HEN_FILE_EXTENSION, ) assert os.path.exists(new_filename) - lc = hen.io.load_lcurve(new_filename) - gti_to_test = hen.io.load_events(self.ev_fileAcal).gti[0] + lc = io.load_lcurve(new_filename) + gti_to_test = io.load_events(self.ev_fileAcal).gti[0] assert np.allclose(gti_to_test, lc.gti) def test_fits_lcurve0(self): @@ -207,14 +219,14 @@ def test_fits_lcurve0(self): out = os.path.join(self.datadir, "lcurve_lc") command = f"{self.ev_fileAcal} --outfile {out}" - hen.lcurve.main(command.split()) + lcurve.main(command.split()) assert os.path.exists(os.path.join(self.datadir, "lcurve_lc") + HEN_FILE_EXTENSION) command = f"--fits-input {lcurve_ftools_orig} --outfile {lcurve_ftools}" - hen.lcurve.main(command.split()) + lcurve.main(command.split()) with pytest.warns(AstropyUserWarning, match="File exists, and noclobber"): command = command + " --noclobber" - hen.lcurve.main(command.split()) + lcurve.main(command.split()) def test_fits_lcurve1(self): """Test light curves from FITS.""" @@ -222,8 +234,8 @@ def test_fits_lcurve1(self): lcurve_mp = os.path.join(self.datadir, "lcurve_lc" + HEN_FILE_EXTENSION) - _, lcdata_mp = hen.io.get_file_type(lcurve_mp, raw_data=False) - _, lcdata_ftools = hen.io.get_file_type(lcurve_ftools, raw_data=False) + _, lcdata_mp = io.get_file_type(lcurve_mp, raw_data=False) + _, lcdata_ftools = io.get_file_type(lcurve_ftools, raw_data=False) lc_mp = lcdata_mp.counts @@ -239,18 +251,18 @@ def test_fits_lcurve1(self): def test_txt_lcurve(self): """Test light curves from txt.""" lcurve_mp = os.path.join(self.datadir, "lcurve_lc" + HEN_FILE_EXTENSION) - _, lcdata_mp = hen.io.get_file_type(lcurve_mp, raw_data=False) + _, lcdata_mp = io.get_file_type(lcurve_mp, raw_data=False) lc_mp = lcdata_mp.counts time_mp = lcdata_mp.time lcurve_txt_orig = os.path.join(self.datadir, "lcurve_txt_lc.txt") - hen.io.save_as_ascii([time_mp, lc_mp], lcurve_txt_orig) + io.save_as_ascii([time_mp, lc_mp], lcurve_txt_orig) lcurve_txt = os.path.join(self.datadir, "lcurve_txt_lc" + HEN_FILE_EXTENSION) command = "--txt-input " + lcurve_txt_orig + " --outfile " + lcurve_txt - hen.lcurve.main(command.split()) - lcdata_txt = hen.io.get_file_type(lcurve_txt, raw_data=False)[1] + lcurve.main(command.split()) + lcdata_txt = io.get_file_type(lcurve_txt, raw_data=False)[1] lc_txt = lcdata_txt.counts @@ -260,7 +272,7 @@ def test_txt_lcurve(self): with pytest.warns(AstropyUserWarning, match="File exists, and noclobber"): command = command + " --noclobber" - hen.lcurve.main(command.split()) + lcurve.main(command.split()) def test_joinlcs(self): """Test produce joined light curves.""" @@ -271,15 +283,15 @@ def test_joinlcs(self): ) lcA_pattern = "monol_testA_nustar_fpma_gti[0-9][0-9][0-9]_lc*" lcB_pattern = "monol_testB_nustar_fpmb_gti[0-9][0-9][0-9]_lc*" - hen.lcurve.join_lightcurves( + lcurve.join_lightcurves( glob.glob(os.path.join(self.datadir, lcA_pattern + HEN_FILE_EXTENSION)) + glob.glob(os.path.join(self.datadir, lcB_pattern + HEN_FILE_EXTENSION)), new_filename, ) - lc = hen.io.load_lcurve(new_actual_filename) + lc = io.load_lcurve(new_actual_filename) assert hasattr(lc, "gti") - gti_to_test = hen.io.load_events(self.ev_fileA).gti + gti_to_test = io.load_events(self.ev_fileA).gti assert np.allclose(gti_to_test, lc.gti) def test_scrunchlcs(self): @@ -289,15 +301,15 @@ def test_scrunchlcs(self): out = os.path.join(self.datadir, "monol_test_scrunchlc" + HEN_FILE_EXTENSION) command = f"{a_in} {b_in} -o {out}" - a_lc = hen.io.load_lcurve(a_in) - b_lc = hen.io.load_lcurve(b_in) + a_lc = io.load_lcurve(a_in) + b_lc = io.load_lcurve(b_in) a_lc.apply_gtis() b_lc.apply_gtis() - hen.lcurve.scrunch_main(command.split()) - out_lc = hen.io.load_lcurve(out) + lcurve.scrunch_main(command.split()) + out_lc = io.load_lcurve(out) out_lc.apply_gtis() assert np.all(out_lc.counts == a_lc.counts + b_lc.counts) - gti_to_test = hen.io.load_events(self.ev_fileA).gti + gti_to_test = io.load_events(self.ev_fileA).gti assert np.allclose(gti_to_test, out_lc.gti) def testbaselinelc(self): @@ -306,10 +318,10 @@ def testbaselinelc(self): out = os.path.join(self.datadir, "monol_test_baselc") command = f"{a_in} -o {out} -p 0.001 --lam 1e5" - hen.lcurve.baseline_main(command.split()) - out_lc = hen.io.load_lcurve(out + "_0" + HEN_FILE_EXTENSION) + lcurve.baseline_main(command.split()) + out_lc = io.load_lcurve(out + "_0" + HEN_FILE_EXTENSION) assert hasattr(out_lc, "base") - gti_to_test = hen.io.load_events(self.ev_fileA).gti + gti_to_test = io.load_events(self.ev_fileA).gti assert np.allclose(gti_to_test, out_lc.gti) def testbaselinelc_nooutroot(self): @@ -317,10 +329,10 @@ def testbaselinelc_nooutroot(self): a_in = os.path.join(self.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) command = f"{a_in} -p 0.001 --lam 1e5" - hen.lcurve.baseline_main(command.split()) - out_lc = hen.io.load_lcurve(hen.base.hen_root(a_in) + "_lc_baseline" + HEN_FILE_EXTENSION) + lcurve.baseline_main(command.split()) + out_lc = io.load_lcurve(base.hen_root(a_in) + "_lc_baseline" + HEN_FILE_EXTENSION) assert hasattr(out_lc, "base") - gti_to_test = hen.io.load_events(self.ev_fileA).gti + gti_to_test = io.load_events(self.ev_fileA).gti assert np.allclose(gti_to_test, out_lc.gti) def test_lcurve_error_uncalibrated(self): @@ -332,7 +344,7 @@ def test_lcurve_error_uncalibrated(self): command = f"{data} -e 3 50" with pytest.raises(ValueError, match="Did you run HENcalibrate?"): - hen.lcurve.main(command.split()) + lcurve.main(command.split()) def test_lcurve_pi_filtering(self): """Test light curve using PI filtering.""" @@ -342,42 +354,42 @@ def test_lcurve_pi_filtering(self): ) command = f"{data} --pi-interval {10} {300}" - hen.lcurve.main(command.split()) + lcurve.main(command.split()) def test_rebinlc(self): """Test LC rebinning.""" data = os.path.join(self.datadir, "monol_testA_E3-50_lc") + HEN_FILE_EXTENSION command = f"{data} -r 4" - hen.rebin.main(command.split()) + rebin.main(command.split()) def test_save_fvar_from_lc(self): fname = os.path.join(self.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) - hen.exvar.main([fname, "-c", "10", "--fraction-step", "0.6", "--norm", "fvar"]) - out = hen.base.hen_root(fname) + "_fvar" + ".qdp" + exvar.main([fname, "-c", "10", "--fraction-step", "0.6", "--norm", "fvar"]) + out = base.hen_root(fname) + "_fvar" + ".qdp" os.path.exists(out) def test_save_excvar_from_lc(self): fname = os.path.join(self.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) - hen.exvar.main([fname]) - out = hen.base.hen_root(fname) + "_excvar" + ".qdp" + exvar.main([fname]) + out = base.hen_root(fname) + "_excvar" + ".qdp" os.path.exists(out) def test_save_excvar_norm_from_lc(self): fname = os.path.join(self.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) - hen.exvar.main([fname, "--norm", "norm_excvar"]) - out = hen.base.hen_root(fname) + "_norm_excvar" + ".qdp" + exvar.main([fname, "--norm", "norm_excvar"]) + out = base.hen_root(fname) + "_norm_excvar" + ".qdp" os.path.exists(out) def test_save_excvar_wrong_norm_from_lc(self): fname = os.path.join(self.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) with pytest.raises(ValueError, match="Normalization must be fvar,"): - hen.exvar.main([fname, "--norm", "cicciput"]) + exvar.main([fname, "--norm", "cicciput"]) def test_create_gti_lc(self): """Test creating a GTI file.""" fname = os.path.join(self.datadir, "monol_testA_E3-50_lc") + HEN_FILE_EXTENSION command = f"{fname} -f counts>0 -c --debug" - hen.create_gti.main(command.split()) + create_gti.main(command.split()) def test_apply_gti_lc(self): """Test applying a GTI file.""" @@ -385,13 +397,13 @@ def test_apply_gti_lc(self): lcfname = os.path.join(self.datadir, "monol_testA_E3-50_lc") + HEN_FILE_EXTENSION lcoutname = os.path.join(self.datadir, "monol_testA_E3-50_lc_gtifilt") + HEN_FILE_EXTENSION command = f"{lcfname} -a {fname} --debug" - hen.create_gti.main(command.split()) - hen.io.load_lcurve(lcoutname) + create_gti.main(command.split()) + io.load_lcurve(lcoutname) def test_plot_lcurve_baseline(self): a_in = os.path.join(self.datadir, "monol_testA_E3-50_lc" + HEN_FILE_EXTENSION) - base_file = hen.base.hen_root(a_in) + "_lc_baseline" + HEN_FILE_EXTENSION - hen.plot.main([base_file, "--noplot", "-o", "dummy_base.qdp"]) + base_file = base.hen_root(a_in) + "_lc_baseline" + HEN_FILE_EXTENSION + plot.main([base_file, "--noplot", "-o", "dummy_base.qdp"]) filedata = np.genfromtxt("dummy_base.qdp") assert filedata.shape[1] == 3 @@ -400,13 +412,13 @@ def test_pds_fits(self): """Test PDS production with light curves obtained from FITS files.""" lcurve_ftools = os.path.join(self.datadir, "lcurve_ftools_lc" + HEN_FILE_EXTENSION) command = f"{lcurve_ftools} --save-all -f 128" - hen.fspec.main(command.split()) + fspec.main(command.split()) def test_pds_txt(self): """Test PDS production with light curves obtained from txt files.""" lcurve_txt = os.path.join(self.datadir, "lcurve_txt_lc" + HEN_FILE_EXTENSION) command = f"{lcurve_txt} --save-all -f 128" - hen.fspec.main(command.split()) + fspec.main(command.split()) def test_exposure(self): """Test exposure calculations from unfiltered files.""" @@ -414,10 +426,10 @@ def test_exposure(self): ufname = os.path.join(self.datadir, "monol_testA_uf.evt") command = f"{lcname} {ufname}" - hen.exposure.main(command.split()) + exposure.main(command.split()) fname = os.path.join(self.datadir, "monol_testA_E3-50_lccorr" + HEN_FILE_EXTENSION) assert os.path.exists(fname) - ftype, contents = hen.io.get_file_type(fname) + ftype, contents = io.get_file_type(fname) assert isinstance(contents, Lightcurve) assert hasattr(contents, "expo") diff --git a/hendrics/tests/test_phaseogram.py b/hendrics/tests/test_phaseogram.py index f914b0bd..5c689403 100644 --- a/hendrics/tests/test_phaseogram.py +++ b/hendrics/tests/test_phaseogram.py @@ -8,7 +8,7 @@ from stingray.lightcurve import Lightcurve from astropy.io.fits import Header -from hendrics.base import hen_root +from hendrics.base import hen_root, HAS_PINT from hendrics.efsearch import main_zsearch from hendrics.io import HEN_FILE_EXTENSION, load_folding, save_events from hendrics.phaseogram import ( diff --git a/hendrics/tests/test_read_events.py b/hendrics/tests/test_read_events.py index 8a391aeb..d1c54deb 100644 --- a/hendrics/tests/test_read_events.py +++ b/hendrics/tests/test_read_events.py @@ -6,8 +6,8 @@ import pytest from stingray.events import EventList -import hendrics as hen from astropy.utils import minversion +from hendrics import io, lcurve, read_events from hendrics.fake import main from hendrics.io import ( HEN_FILE_EXTENSION, @@ -78,7 +78,7 @@ def setup_class(cls): def test_merge_events(self): with pytest.warns(UserWarning, match="changing MJDREF"): - hen.read_events.main_join( + read_events.main_join( [ self.f0, self.f1, @@ -93,7 +93,7 @@ def test_merge_events(self): def test_merge_events_different_instr(self): with pytest.warns(UserWarning): - hen.read_events.main_join( + read_events.main_join( [ self.f0, self.f3, @@ -107,7 +107,7 @@ def test_merge_events_different_instr(self): os.unlink(out) def test_merge_events_different_instr_ignore(self): - hen.read_events.main_join( + read_events.main_join( [ self.f0, self.f2, @@ -125,7 +125,7 @@ def test_merge_events_different_instr_ignore(self): os.unlink(out) def test_merge_two_events_different_instr_ignore(self): - hen.read_events.main_join( + read_events.main_join( [ self.f0, self.f3, @@ -143,7 +143,7 @@ def test_merge_two_events_different_instr_ignore(self): def test_merge_events_no_out_fname(self): with pytest.warns(UserWarning, match="changing MJDREF"): - hen.read_events.main_join([self.f0, self.f1]) + read_events.main_join([self.f0, self.f1]) out = os.path.join(self.datadir, "ev_ev" + HEN_FILE_EXTENSION) assert os.path.exists(out) os.unlink(out) @@ -154,14 +154,14 @@ def test_merge_many_events_warnings(self): UserWarning, match=f"{os.path.split(self.f1)[1]}.* has a different MJDREF", ): - hen.read_events.main_join([self.f0, self.f1, self.f2, "-o", out]) + read_events.main_join([self.f0, self.f1, self.f2, "-o", out]) assert os.path.exists(out) os.unlink(out) with pytest.warns( UserWarning, match=f"{os.path.split(self.f3)[1]}.* is from a different", ): - hen.read_events.main_join([self.f0, self.f2, self.f3, "-o", out]) + read_events.main_join([self.f0, self.f2, self.f3, "-o", out]) assert os.path.exists(out) os.unlink(out) @@ -169,7 +169,7 @@ def test_merge_many_events_warnings(self): UserWarning, match=f"{os.path.split(self.f4)[1]}.* has no good events", ): - hen.read_events.main_join([self.f0, self.f2, self.f4, "-o", out]) + read_events.main_join([self.f0, self.f2, self.f4, "-o", out]) assert os.path.exists(out) os.unlink(out) @@ -177,7 +177,7 @@ def test_merge_many_events(self): outfile = "joint_ev" + HEN_FILE_EXTENSION # Note that only 0 and 2 are valid with pytest.warns(UserWarning): - hen.read_events.main_join([self.f0, self.f2, self.f3]) + read_events.main_join([self.f0, self.f2, self.f3]) assert os.path.exists(outfile) @@ -315,7 +315,7 @@ def test_split_events(self): filea = os.path.join(self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) - files = hen.read_events.main_splitevents([filea, "-l", "50"]) + files = read_events.main_splitevents([filea, "-l", "50"]) for f in files: assert os.path.exists(f) @@ -327,7 +327,7 @@ def test_split_events_at_mjd(self): mean_met = np.mean(data.time) mean_mjd = mean_met / 86400 + data.mjdref - files = hen.read_events.main_splitevents([filea, "--split-at-mjd", f"{mean_mjd}"]) + files = read_events.main_splitevents([filea, "--split-at-mjd", f"{mean_mjd}"]) assert "before" in files[0] assert "after" in files[1] @@ -342,13 +342,13 @@ def test_split_events_bad_overlap_raises(self): filea = os.path.join(self.datadir, "monol_testA_nustar_fpma_ev" + HEN_FILE_EXTENSION) with pytest.raises(ValueError, match="Overlap cannot be >=1. Exiting."): - hen.read_events.split_eventlist(filea, 10, overlap=1.5) + read_events.split_eventlist(filea, 10, overlap=1.5) def test_load_events(self): """Test event file reading.""" command = f"{self.fits_fileA}" - hen.read_events.main(command.split()) - ev = hen.io.load_events(self.ev_fileA) + read_events.main(command.split()) + ev = io.load_events(self.ev_fileA) assert hasattr(ev, "header") assert hasattr(ev, "gti") @@ -360,38 +360,38 @@ def test_load_events_with_2_cpus(self): os.path.join(self.datadir, "monol_testB.evt"), os.path.join(self.datadir, "monol_testA_timezero.evt"), ) - hen.read_events.main(command.split()) + read_events.main(command.split()) def test_load_events_split(self): """Test event file splitting.""" command = f"{self.fits_fileB} -g --min-length 0" - hen.read_events.main(command.split()) + read_events.main(command.split()) new_filename = os.path.join( self.datadir, "monol_testB_nustar_fpmb_gti000_ev" + HEN_FILE_EXTENSION, ) assert os.path.exists(new_filename) command = f"{new_filename}" - hen.lcurve.main(command.split()) + lcurve.main(command.split()) new_filename = os.path.join( self.datadir, "monol_testB_nustar_fpmb_gti000_lc" + HEN_FILE_EXTENSION, ) assert os.path.exists(new_filename) - lc = hen.io.load_lcurve(new_filename) - gti_to_test = hen.io.load_events(self.ev_fileB).gti[0] + lc = io.load_lcurve(new_filename) + gti_to_test = io.load_events(self.ev_fileB).gti[0] assert np.allclose(gti_to_test, lc.gti) def test_load_events_noclobber(self): """Test event file reading w. noclobber option.""" with pytest.warns(UserWarning, match="exists and using noclobber. Skipping"): command = f"{self.fits_fileB} --noclobber" - hen.read_events.main(command.split()) + read_events.main(command.split()) def test_fix_gaps_events(self): """Test event file reading w. noclobber option.""" command = f"{self.fits_fileB} --fill-small-gaps 4" - hen.read_events.main(command.split()) + read_events.main(command.split()) @classmethod def teardown_class(cls): From 0862a0ac59e35b13efe830f5065ad0edd8fe5de9 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 11:18:38 +0200 Subject: [PATCH 41/58] Sort imports --- hendrics/tests/test_base.py | 2 +- hendrics/tests/test_binary.py | 4 ++-- hendrics/tests/test_calibrate.py | 2 +- hendrics/tests/test_colors.py | 2 +- hendrics/tests/test_efsearch.py | 4 ++-- hendrics/tests/test_fake.py | 4 +--- hendrics/tests/test_fspec.py | 2 +- hendrics/tests/test_gti.py | 3 ++- hendrics/tests/test_io.py | 2 +- hendrics/tests/test_lc.py | 16 ++++++++-------- hendrics/tests/test_phaseogram.py | 2 +- 11 files changed, 21 insertions(+), 22 deletions(-) diff --git a/hendrics/tests/test_base.py b/hendrics/tests/test_base.py index 6449deff..72650f49 100644 --- a/hendrics/tests/test_base.py +++ b/hendrics/tests/test_base.py @@ -4,7 +4,7 @@ import pytest from stingray.events import EventList -from hendrics.base import deorbit_events, normalize_dyn_profile, HAS_PINT +from hendrics.base import HAS_PINT, deorbit_events, normalize_dyn_profile from hendrics.tests import _dummy_par diff --git a/hendrics/tests/test_binary.py b/hendrics/tests/test_binary.py index 749115d8..b34c644d 100644 --- a/hendrics/tests/test_binary.py +++ b/hendrics/tests/test_binary.py @@ -5,9 +5,9 @@ import pytest -from hendrics.tests import _dummy_par -from hendrics import binary, io, calibrate, lcurve, read_events +from hendrics import binary, calibrate, io, lcurve, read_events from hendrics.base import HAS_PINT +from hendrics.tests import _dummy_par from . import cleanup_test_dir diff --git a/hendrics/tests/test_calibrate.py b/hendrics/tests/test_calibrate.py index b318b58e..e1d98bb7 100644 --- a/hendrics/tests/test_calibrate.py +++ b/hendrics/tests/test_calibrate.py @@ -3,10 +3,10 @@ import numpy as np import pytest +from hendrics import calibrate, fake, io, read_events from hendrics.calibrate import default_nustar_rmf from hendrics.io import load_events, save_events from hendrics.tests import _dummy_par -from hendrics import calibrate, io, read_events, fake from . import cleanup_test_dir diff --git a/hendrics/tests/test_colors.py b/hendrics/tests/test_colors.py index 6e80622d..b78c678d 100644 --- a/hendrics/tests/test_colors.py +++ b/hendrics/tests/test_colors.py @@ -6,8 +6,8 @@ import numpy as np import pytest -from hendrics import colors, io, lcurve, plot, read_events, calibrate from astropy import log +from hendrics import calibrate, colors, io, lcurve, plot, read_events from hendrics.tests import _dummy_par from . import cleanup_test_dir diff --git a/hendrics/tests/test_efsearch.py b/hendrics/tests/test_efsearch.py index d8b06c4a..bfb04795 100644 --- a/hendrics/tests/test_efsearch.py +++ b/hendrics/tests/test_efsearch.py @@ -8,11 +8,11 @@ from stingray.events import EventList from stingray.lightcurve import Lightcurve -from hendrics.base import hen_root, HAS_PINT +from hendrics.base import HAS_PINT, hen_root from hendrics.efsearch import ( + HAS_IMAGEIO, decide_binary_parameters, folding_orbital_search, - HAS_IMAGEIO, main_accelsearch, main_efsearch, main_z2vspf, diff --git a/hendrics/tests/test_fake.py b/hendrics/tests/test_fake.py index 60affdac..4f55b370 100644 --- a/hendrics/tests/test_fake.py +++ b/hendrics/tests/test_fake.py @@ -9,10 +9,8 @@ from astropy import log from astropy.io import fits - -from hendrics import fake, io, read_events, calibrate, base +from hendrics import base, calibrate, fake, io, read_events from hendrics.base import HAS_PINT - from hendrics.fake import scramble from hendrics.io import load_events from hendrics.tests import _dummy_par diff --git a/hendrics/tests/test_fspec.py b/hendrics/tests/test_fspec.py index 8fbf2492..4845aef5 100644 --- a/hendrics/tests/test_fspec.py +++ b/hendrics/tests/test_fspec.py @@ -16,8 +16,8 @@ from astropy import log from hendrics import ( base, - io, fspec, + io, lcurve, modeling, plot, diff --git a/hendrics/tests/test_gti.py b/hendrics/tests/test_gti.py index 3de66403..072a626f 100644 --- a/hendrics/tests/test_gti.py +++ b/hendrics/tests/test_gti.py @@ -4,8 +4,9 @@ import os from astropy import log +from hendrics import calibrate, create_gti, io, lcurve, read_events from hendrics.tests import _dummy_par -from hendrics import io, create_gti, lcurve, read_events, calibrate + from . import cleanup_test_dir try: diff --git a/hendrics/tests/test_io.py b/hendrics/tests/test_io.py index 8d903328..c26004a9 100644 --- a/hendrics/tests/test_io.py +++ b/hendrics/tests/test_io.py @@ -18,8 +18,8 @@ from astropy.modeling.core import Model from hendrics.base import hen_root from hendrics.io import ( - HAS_H5PY, HAS_C256, + HAS_H5PY, HEN_FILE_EXTENSION, _split_high_precision_number, find_file_in_allowed_paths, diff --git a/hendrics/tests/test_lc.py b/hendrics/tests/test_lc.py index a37883b5..22572c2c 100644 --- a/hendrics/tests/test_lc.py +++ b/hendrics/tests/test_lc.py @@ -9,24 +9,24 @@ from astropy import log from astropy.logger import AstropyUserWarning -from hendrics.io import HEN_FILE_EXTENSION, get_file_type -from hendrics.lcurve import lcurve_from_events -from hendrics.read_events import treat_event_file -from hendrics.tests import _dummy_par - from hendrics import ( base, calibrate, create_gti, + exposure, exvar, fspec, io, + lcurve, plot, - rebin, read_events, - lcurve, - exposure, + rebin, ) +from hendrics.io import HEN_FILE_EXTENSION, get_file_type +from hendrics.lcurve import lcurve_from_events +from hendrics.read_events import treat_event_file +from hendrics.tests import _dummy_par + from . import cleanup_test_dir try: diff --git a/hendrics/tests/test_phaseogram.py b/hendrics/tests/test_phaseogram.py index 5c689403..adf66b10 100644 --- a/hendrics/tests/test_phaseogram.py +++ b/hendrics/tests/test_phaseogram.py @@ -8,7 +8,7 @@ from stingray.lightcurve import Lightcurve from astropy.io.fits import Header -from hendrics.base import hen_root, HAS_PINT +from hendrics.base import HAS_PINT, hen_root from hendrics.efsearch import main_zsearch from hendrics.io import HEN_FILE_EXTENSION, load_folding, save_events from hendrics.phaseogram import ( From 1f37b63ef447e1e4d3d2efe9b3beed4132e7d180 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 11:20:47 +0200 Subject: [PATCH 42/58] Fix ruff scope --- .ruff.toml | 1 + pyproject.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/.ruff.toml b/.ruff.toml index 50fd16f2..7fcecc97 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -198,6 +198,7 @@ lint.unfixable = [ "test_*.py" = [ "PTH", # all flake8-use-pathlib "RUF015", # Prefer next({iterable}) over single element slice + "F401", ] # TODO: fix these, on a per-subpackage basis. # When a general exclusion is being fixed, but it affects many subpackages, it diff --git a/pyproject.toml b/pyproject.toml index c92cf9ac..c7393fdd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -301,6 +301,7 @@ exclude=[ "notebooks/*.ipynb", "*.svg", "docs/conf.py", + "docs/scripts/cli.rst", "_astropy_init.py", "__init__.py", "compatibility.py", From 422a31e62dd743f3db82db4fd2e1de81647e930c Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 11:24:38 +0200 Subject: [PATCH 43/58] Format docstrings --- hendrics/base.py | 3 +-- hendrics/compat/compatibility.py | 2 +- hendrics/efsearch.py | 5 ++--- hendrics/exposure.py | 6 ++---- hendrics/exvar.py | 3 +-- hendrics/ffa.py | 8 +++----- hendrics/fold.py | 10 +++------- hendrics/fspec.py | 2 -- hendrics/io.py | 6 +++--- hendrics/lcurve.py | 8 ++------ hendrics/ml_timing.py | 8 ++++---- hendrics/phasetag.py | 1 - hendrics/plot.py | 1 - hendrics/read_events.py | 3 +-- 14 files changed, 23 insertions(+), 43 deletions(-) diff --git a/hendrics/base.py b/hendrics/base.py index 0af92cd3..75a2135b 100644 --- a/hendrics/base.py +++ b/hendrics/base.py @@ -1071,7 +1071,6 @@ def memmapped_arange(i0, i1, istep, fname=None, nbin_threshold=10**7, dtype=floa >>> assert np.allclose(np.arange(i0, i1, istep), memmapped_arange(i0, i1, istep)) >>> i0, i1, istep = 0, 10, 1e-7 >>> assert np.allclose(np.arange(i0, i1, istep), memmapped_arange(i0, i1, istep)) - """ import tempfile @@ -1092,7 +1091,7 @@ def memmapped_arange(i0, i1, istep, fname=None, nbin_threshold=10**7, dtype=floa def nchars_in_int_value(value): - """Number of characters to write an integer number + """Number of characters to write an integer number. Examples -------- diff --git a/hendrics/compat/compatibility.py b/hendrics/compat/compatibility.py index b432eb18..bfe08e21 100644 --- a/hendrics/compat/compatibility.py +++ b/hendrics/compat/compatibility.py @@ -53,6 +53,6 @@ def __call__(self, func): def array_take(arr, indices): # pragma: no cover - """Adapt np.take to arrays""" + """Adapt np.take to arrays.""" warnings.warn("array_take is deprecated. Use np.take instead, also with Numba.") return np.take(arr, indices) diff --git a/hendrics/efsearch.py b/hendrics/efsearch.py index d2cb8512..3818dc92 100644 --- a/hendrics/efsearch.py +++ b/hendrics/efsearch.py @@ -100,8 +100,7 @@ def find_nearest_contour(cs, x, y, indices=None, pixel=True): - """ - Find the point in the contour plot that is closest to ``(x, y)``. + """Find the point in the contour plot that is closest to ``(x, y)``. This method does not support filled contours. @@ -1178,7 +1177,7 @@ def get_xy_boundaries_from_level(x, y, image, level, x0, y0): def get_boundaries_from_level(x, y, level, x0): - """Calculate boundaries of peak in x-y plot + """Calculate boundaries of peak in x-y plot. Parameters ---------- diff --git a/hendrics/exposure.py b/hendrics/exposure.py index a7836a00..f9703447 100644 --- a/hendrics/exposure.py +++ b/hendrics/exposure.py @@ -1,8 +1,8 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """Calculate the exposure correction for light curves. -Only works for data taken in specific data modes of NuSTAR, where all events -are telemetered. +Only works for data taken in specific data modes of NuSTAR, where all +events are telemetered. """ import warnings @@ -44,7 +44,6 @@ def get_livetime_per_bin(times, events, priors, dt=None, gti=None): gti : [[g0_0, g0_1], [g1_0, g1_1], ...] Good time intervals. Defaults to [[time[0] - dt[0]/2, time[-1] + dt[-1]/2]] - """ assert len(events) == len(priors), "`events` and `priors` must be of the same length" @@ -228,7 +227,6 @@ def get_exposure_from_uf(time, uf_file, dt=None, gti=None): ---------------- dt : float If time array is not sampled uniformly, dt can be specified here. - """ dt = _assign_value_if_none(dt, np.median(np.diff(time))) diff --git a/hendrics/exvar.py b/hendrics/exvar.py index 148a3368..798e7fe4 100644 --- a/hendrics/exvar.py +++ b/hendrics/exvar.py @@ -1,5 +1,4 @@ -""" -Created on Thu Aug 17 08:55:47 2017 +"""Created on Thu Aug 17 08:55:47 2017. @author: marta """ diff --git a/hendrics/ffa.py b/hendrics/ffa.py index 3682f85f..40ef6e9f 100644 --- a/hendrics/ffa.py +++ b/hendrics/ffa.py @@ -6,7 +6,6 @@ from .base import show_progress __all__ = ["ffa_search", "h_test", "z_n_fast_cached", "z_n_fast_cached_all"] - """ prof_n step0 step1 step2 0 0+1 0+2 0+4 @@ -139,7 +138,7 @@ def z_n_fast_cached(norm, n=2): @njit() def _z_n_fast_cached_all(norm, cached_sin, cached_cos, ks): - """Numba-compiled core of z_n_fast_cached_all""" + """Numba-compiled core of z_n_fast_cached_all.""" total_norm = np.sum(norm) all_zs = np.zeros(ks.size) @@ -198,7 +197,6 @@ def z_n_fast_cached_all(norm, nmax=20): def h_test(norm, nmax=20): """H statistics, a` la de Jager+89, A&A, 221, 180, eq. 11. - Examples -------- >>> phase = 2 * np.pi * np.arange(0, 1, 0.01) @@ -272,7 +270,7 @@ def sum_arrays(arr1, arr2): def sum_rolled(arr1, arr2, out, shift): - """Sum arr1 with a rolled version of arr2 + """Sum arr1 with a rolled version of arr2. Examples -------- @@ -332,7 +330,7 @@ def _ffa(array_reshaped, bin_period, ntables, z_n_n=2): def ffa(array, bin_period, z_n_n=2): - """Fast folding algorithm search""" + """Fast folding algorithm search.""" N_raw = len(array) ntables = int(2 ** np.ceil(np.log2(N_raw // bin_period + 1))) if ntables <= 1: diff --git a/hendrics/fold.py b/hendrics/fold.py index f8af1209..50dd635b 100644 --- a/hendrics/fold.py +++ b/hendrics/fold.py @@ -474,9 +474,7 @@ def _check_odd(n): def dbl_cos_fit_func(p, x): # the frequency is fixed - """ - A double sinus (fundamental + 1st harmonic) used as a fit function - """ + """A double sinus (fundamental + 1st harmonic) used as a fit function.""" startidx = 0 base = 0 if len(p) % 2 != 0: @@ -498,8 +496,7 @@ def std_residuals(p, x, y): def adjust_amp_phase(pars): - """Give the phases in the interval between 0 and 1. - The calculation is based on the amplitude and phase given as input + """Give the phases in the interval between 0 and 1. The calculation is based on the amplitude and phase given as input. pars[0] is the initial amplitude; pars[1] is the initial phase If amplitude is negative, it makes it positive and changes the phase @@ -520,8 +517,7 @@ def adjust_amp_phase(pars): def fit_profile_with_sinusoids(profile, profile_err, debug=False, nperiods=1, baseline=False): - """ - Fit a folded profile with the std_fold_fit_func. + """Fit a folded profile with the std_fold_fit_func. Tries a number of different initial values for the fit, and returns the result of the best chi^2 fit diff --git a/hendrics/fspec.py b/hendrics/fspec.py index 74a0a3d4..6a123865 100644 --- a/hendrics/fspec.py +++ b/hendrics/fspec.py @@ -258,7 +258,6 @@ def calc_pds( Maximum energy of the photons lombscargle : bool Use the Lomb-Scargle periodogram instead of AveragedPowerspectrum - """ root = hen_root(lcfile) label = "" @@ -382,7 +381,6 @@ def calc_cpds( Maximum energy of the photons lombscargle : bool Use the Lomb-Scargle periodogram instead of AveragedPowerspectrum - """ label = "" if emin is not None or emax is not None: diff --git a/hendrics/io.py b/hendrics/io.py index 48f1eb4d..456d3bfb 100644 --- a/hendrics/io.py +++ b/hendrics/io.py @@ -473,8 +473,8 @@ def recognize_stingray_table(obj): def get_file_type(fname, raw_data=False): """Return the file type and its contents. - Only works for hendrics-format pickle or netcdf files, - or stingray outputs. + Only works for hendrics-format pickle or netcdf files, or stingray + outputs. """ contents_raw = load_data(fname) if isinstance(contents_raw, Table): @@ -597,7 +597,7 @@ def load_timeseries(fname): # ----- functions to save and load LCURVE data def save_lcurve(lcurve, fname, lctype="Lightcurve"): - """Save Light curve to file + """Save Light curve to file. Parameters ---------- diff --git a/hendrics/lcurve.py b/hendrics/lcurve.py index d532a0a3..743e3191 100644 --- a/hendrics/lcurve.py +++ b/hendrics/lcurve.py @@ -111,7 +111,6 @@ def join_lightcurves(lcfilelist, outfile="out_lc" + HEN_FILE_EXTENSION): -------- scrunch_lightcurves : Create a single light curve from input light curves. - """ lcdatas = [] @@ -339,7 +338,6 @@ def lcurve_from_events( Output file noclobber : bool If True, do not overwrite existing files - """ log.info(f"Loading file {f}...") evdata = load_events(f) @@ -503,8 +501,7 @@ def lcurve_from_fits( noclobber=False, outdir=None, ): - """ - Load a lightcurve from a fits file and save it in HENDRICS format. + """Load a lightcurve from a fits file and save it in HENDRICS format. .. note :: FITS light curve handling is still under testing. @@ -701,8 +698,7 @@ def lcurve_from_txt( mjdref=None, gti=None, ): - """ - Load a lightcurve from a text file. + """Load a lightcurve from a text file. Parameters ---------- diff --git a/hendrics/ml_timing.py b/hendrics/ml_timing.py index 774cd579..3b1b699a 100644 --- a/hendrics/ml_timing.py +++ b/hendrics/ml_timing.py @@ -16,7 +16,7 @@ @vectorize([(int64,), (float32,), (float64,)]) def phases_from_zero_to_one(phase): - """Normalize pulse phases from 0 to 1 + """Normalize pulse phases from 0 to 1. Examples -------- @@ -35,7 +35,7 @@ def phases_from_zero_to_one(phase): @vectorize([(int64,), (float32,), (float64,)]) def phases_around_zero(phase): - """Normalize pulse phases from -0.5 to 0.5 + """Normalize pulse phases from -0.5 to 0.5. Examples -------- @@ -54,7 +54,7 @@ def phases_around_zero(phase): @njit() def poisson_loglike(model, data): - """Loglikelihood for a Poisson distribution + """Loglikelihood for a Poisson distribution. Parameters ---------- @@ -73,7 +73,7 @@ def poisson_loglike(model, data): def normal_loglike(model, input_data): - """Loglikelihood for a Poisson distribution + """Loglikelihood for a Poisson distribution. Parameters ---------- diff --git a/hendrics/phasetag.py b/hendrics/phasetag.py index e0c51c50..732e1176 100644 --- a/hendrics/phasetag.py +++ b/hendrics/phasetag.py @@ -73,7 +73,6 @@ def phase_tag( Plot diagnostics expocorr : bool Use exposure correction when calculating the profile - """ # ---- in MJD ---- if gti is None: diff --git a/hendrics/plot.py b/hendrics/plot.py index f8f41e57..c08aefdf 100644 --- a/hendrics/plot.py +++ b/hendrics/plot.py @@ -181,7 +181,6 @@ def _get_const(models): >>> _get_const(1) >>> _get_const('avdsfa') - """ if isinstance(models, Const1D): return models.amplitude.value diff --git a/hendrics/read_events.py b/hendrics/read_events.py index c4309aaa..4fa2afb1 100644 --- a/hendrics/read_events.py +++ b/hendrics/read_events.py @@ -183,8 +183,7 @@ def _wrap_fun(arglist): def multiple_event_concatenate(event_lists): - """ - Join multiple :class:`EventList` objects into one. + """Join multiple :class:`EventList` objects into one. If both are empty, an empty :class:`EventList` is returned. From e5d83186f170e66091206eaa2e654e5077473cb1 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 11:25:01 +0200 Subject: [PATCH 44/58] Format docstrings --- notebooks/deadtime_model_zhang.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/notebooks/deadtime_model_zhang.py b/notebooks/deadtime_model_zhang.py index f36b0dc9..0afb219b 100644 --- a/notebooks/deadtime_model_zhang.py +++ b/notebooks/deadtime_model_zhang.py @@ -78,7 +78,7 @@ def safe_A(k, r0, td, tb, tau, limit_k=60): def check_A(rate, td, tb, max_k=100): - """Ak ->r0**2tb**2 for k->infty""" + """Ak ->r0**2tb**2 for k->infty.""" tau = 1 / rate r0 = r_det(td, rate) @@ -107,7 +107,7 @@ def safe_B(k, r0, td, tb, tau, limit_k=60): def check_B(rate, td, tb, max_k=100): - """Ak ->r0**2tb**2 for k->infty""" + """Ak ->r0**2tb**2 for k->infty.""" tau = 1 / rate r0 = r_det(td, rate) @@ -164,7 +164,7 @@ def pds_model_zhang(N, rate, td, tb, limit_k=60): def check_pds_rate(td, tb, N=100): - """P -> 2 for rate -> 0, or tau -> infty""" + """P -> 2 for rate -> 0, or tau -> infty.""" plt.figure() for rate in np.logspace(2, -2, 5): p = pds_model_zhang_back(N, rate, td, tb)[1][1:] From a28d882bf7e9e21517c8dc2b99e516c3358f43f4 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 11:25:56 +0200 Subject: [PATCH 45/58] Add docformatter --- .pre-commit-config.yaml | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5e642432..ba67d8d2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -36,7 +36,7 @@ repos: # Checks for the existence of private keys. - id: end-of-file-fixer # Makes sure files end in a newline and only a newline. - exclude: ".*(.*.svg|data.*|extern.*|_templates.*|licenses.*|_static.*|_parsetab.py)$" + exclude: ".*(.*.svg|data.*|extern.*|_templates.*|licenses.*|_static.*|_parsetab.py|cli.rst)$" # - id: fix-encoding-pragma # covered by pyupgrade - id: trailing-whitespace # Trims trailing whitespace. @@ -76,25 +76,25 @@ repos: # hooks: # - id: sp-repo-review - # - repo: https://github.com/PyCQA/docformatter - # # using an untagged rev for forward compatibility with pre-commit 4.0 - # # see https://github.com/PyCQA/docformatter/issues/289 - # # This should be changed back to a tag when (>1.7.5) is released - # rev: 06907d0267368b49b9180eed423fae5697c1e909 - # hooks: - # - id: docformatter - # additional_dependencies: [tomli] - # args: [--in-place, --config, ./pyproject.toml] - # exclude: | - # (?x)( - # test.*\.py | - # hendrics/__init__\.py | - # hendrics/_dev/ | - # hendrics/conftest\.py | - # astropy/version\.py | - # docs/ | - # examples/ - # ) + - repo: https://github.com/PyCQA/docformatter + # using an untagged rev for forward compatibility with pre-commit 4.0 + # see https://github.com/PyCQA/docformatter/issues/289 + # This should be changed back to a tag when (>1.7.5) is released + rev: 06907d0267368b49b9180eed423fae5697c1e909 + hooks: + - id: docformatter + additional_dependencies: [tomli] + args: [--in-place, --config, ./pyproject.toml] + exclude: | + (?x)( + test.*\.py | + hendrics/__init__\.py | + hendrics/_dev/ | + hendrics/conftest\.py | + astropy/version\.py | + docs/ | + examples/ + ) # - repo: local # hooks: From 46d1bcb578f83828c745190f9e624d1bb6a121c4 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 11:27:39 +0200 Subject: [PATCH 46/58] Cleanup --- docs/conf.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 068f708f..c0b1480f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -207,13 +207,8 @@ if not ON_RTD and not ON_TRAVIS: # scripts = dict(conf.items("options.entry_points"))["console_scripts"] - print(pyproject) scripts = pyproject["project"]["scripts"] - print(scripts) - # scripts = dict( - # [(l.strip() for l in line.split("=")) for line in scripts.split("\n") if line.strip() != ""] - # ) import subprocess as sp cli_file = os.path.join(os.getcwd(), "scripts", "cli.rst") From 79f2fb5a27990223d2bf3027c427f0c5ba929ca1 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 11:35:01 +0200 Subject: [PATCH 47/58] Configuration fixes --- MANIFEST.in | 1 - docs/conf.py | 5 ----- setup.py | 2 +- tox.ini | 4 ++-- 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index fd3524ad..551ae6ec 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -5,7 +5,6 @@ include README.rst # include pip-requirements* include CITATION -include setup.cfg include hendrics/tests/coveragerc recursive-include hendrics *.evt *.fits *.rmf recursive-include hendrics/tests/data *.evt *.fits *.rmf diff --git a/docs/conf.py b/docs/conf.py index c0b1480f..c99e5d07 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -41,11 +41,6 @@ import tomli as tomllib from pathlib import Path -# Get configuration information from setup.cfg -from configparser import ConfigParser - -conf = ConfigParser() - ON_RTD = os.environ.get("READTHEDOCS") == "True" ON_TRAVIS = os.environ.get("TRAVIS") == "true" diff --git a/setup.py b/setup.py index d88ba36c..0fa73d60 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst # NOTE: The configuration for the package, including the name, version, and -# other information are set in the setup.cfg file. +# other information are set in the pyproject.toml file. import sys from pathlib import Path diff --git a/tox.ini b/tox.ini index 59a8ed31..25877870 100644 --- a/tox.ini +++ b/tox.ini @@ -59,7 +59,7 @@ deps = devdeps: git+https://github.com/stingraysoftware/stingray.git#egg=stingray alldeps: netcdf4==1.7.0 -# The following indicates which extras_require from setup.cfg will be installed +# The following indicates which extras_require will be installed extras = test alldeps: all @@ -70,7 +70,7 @@ commands = pip freeze !cov: pytest --pyargs hendrics {toxinidir}/docs {posargs} - cov: pytest --pyargs hendrics {toxinidir}/docs --cov hendrics --cov-config={toxinidir}/setup.cfg {posargs} + cov: pytest --pyargs hendrics {toxinidir}/docs --cov hendrics --cov-config={toxinidir}/pyproject.toml {posargs} cov: coverage xml -o {toxinidir}/coverage.xml [testenv:build_docs] From 771e86bc5654362bd8eacfa18a4a2d49e73be2ff Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 11:42:16 +0200 Subject: [PATCH 48/58] Make removesuffix available in Py<3.8 --- hendrics/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hendrics/base.py b/hendrics/base.py index 75a2135b..0f2a44d6 100644 --- a/hendrics/base.py +++ b/hendrics/base.py @@ -1,5 +1,6 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """A miscellaneous collection of basic functions.""" +from __future__ import annotations import copy import os From 812c2a4b9c6473ce7626f17167b1ff1a7313215d Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 11:42:26 +0200 Subject: [PATCH 49/58] Add import --- hendrics/tests/test_io.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hendrics/tests/test_io.py b/hendrics/tests/test_io.py index c26004a9..d6f106b1 100644 --- a/hendrics/tests/test_io.py +++ b/hendrics/tests/test_io.py @@ -20,6 +20,7 @@ from hendrics.io import ( HAS_C256, HAS_H5PY, + HAS_NETCDF, HEN_FILE_EXTENSION, _split_high_precision_number, find_file_in_allowed_paths, From abe069960134f64b32886967ace61e56c9bca9dd Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 11:44:59 +0200 Subject: [PATCH 50/58] Hopefully fix doc tests --- .github/workflows/ci_test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 3b56c95f..67f9e689 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -73,6 +73,7 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install tox + pip install -e ".[docs]" - name: Install system dependencies run: sudo apt-get -y install graphviz pandoc - name: Print Python, pip, setuptools, and tox versions From 37bfd6053168a51ab1e37420b15ac9f8938573b6 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 11:52:15 +0200 Subject: [PATCH 51/58] Cleanup --- hendrics/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hendrics/base.py b/hendrics/base.py index 0f2a44d6..12ce2ba8 100644 --- a/hendrics/base.py +++ b/hendrics/base.py @@ -1,5 +1,6 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst """A miscellaneous collection of basic functions.""" + from __future__ import annotations import copy From f373fc60183da8fb7d0f9f95868e59f02d0aec39 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 11:57:48 +0200 Subject: [PATCH 52/58] Fix version bugs --- docs/hendrics/hendrics.rst | 9 --------- pyproject.toml | 1 + 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/docs/hendrics/hendrics.rst b/docs/hendrics/hendrics.rst index dd04bb50..6ae34dfe 100644 --- a/docs/hendrics/hendrics.rst +++ b/docs/hendrics/hendrics.rst @@ -156,15 +156,6 @@ hendrics.timelags module :undoc-members: :show-inheritance: -hendrics.version module ------------------------ - -.. automodule:: hendrics.version - :members: - :undoc-members: - :show-inheritance: - - Module contents --------------- diff --git a/pyproject.toml b/pyproject.toml index c7393fdd..9de85189 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -267,6 +267,7 @@ filterwarnings = [ "hendrics/*/tests/*", "hendrics/extern/*", "hendrics/version*", + "hendrics/_version*", "*/hendrics/_astropy_init*", "*/hendrics/conftest.py", "*/hendrics/*setup_package*", From 7470cf1c8b8070cce2d9ab21d0aa4f594e29cee2 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 12:06:44 +0200 Subject: [PATCH 53/58] Bump minimum Python version --- .github/workflows/ci_test.yml | 4 ++-- CONTRIBUTING.md | 2 +- docs/install.rst | 2 +- pyproject.toml | 2 +- tox.ini | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci_test.yml b/.github/workflows/ci_test.yml index 67f9e689..68776dd4 100644 --- a/.github/workflows/ci_test.yml +++ b/.github/workflows/ci_test.yml @@ -122,8 +122,8 @@ jobs: use_remote_data: true continue-on-error: true - os: ubuntu-latest - python: '3.8' - tox_env: 'py38-test-oldestdeps-cov' + python: '3.9' + tox_env: 'py39-test-oldestdeps-cov' use_remote_data: true - os: macos-latest python: '3.11' diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 543972d5..4f39a062 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,5 +4,5 @@ and/or get involved in our [Slack channel ](https://join.slack.com/t/stingraysof Please follow the [Astropy contribution guidelines](https://docs.astropy.org/en/stable/development/workflow/development_workflow.html), and the [Astropy coding guidelines](https://docs.astropy.org/en/stable/development/codeguide.html#coding-style-conventions). -This code is written in Python 3.8+ +This code is written in Python 3.9+ Tests run at each commit during Pull Requests, so it is easy to single out points in the code that break this compatibility. diff --git a/docs/install.rst b/docs/install.rst index e8a58160..fd1e019b 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -4,7 +4,7 @@ Installation Instructions Prerequisites ------------- -You'll need a recent python 3.8+ installation. +You'll need a recent python 3.9+ installation. The main dependency is 1. `Stingray `__, diff --git a/pyproject.toml b/pyproject.toml index 9de85189..e5cdfe53 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ authors = [ { name = "Matteo Bachetti", email = "matteo@matteobachetti.it" } ] license = { text = "3-clause BSD" } -requires-python = ">=3.8" +requires-python = ">=3.9" classifiers = [ "Intended Audience :: Science/Research", "License :: OSI Approved :: BSD License", diff --git a/tox.ini b/tox.ini index 25877870..df65fa1c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] envlist = - py{38,39,310,311,312}-test{,-alldeps,-devdeps,-oldestdeps}{,-cov} - py{38,39,310,311,312}-test-astropy{4,5,lts} + py{39,310,311,312}-test{,-alldeps,-devdeps,-oldestdeps}{,-cov} + py{39,310,311,312}-test-astropy{4,5,lts} build_docs linkcheck codestyle From 07aa7f745779131713f8802f89278972b1d09a54 Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 12:26:03 +0200 Subject: [PATCH 54/58] Fix for old and new matplotlib --- hendrics/efsearch.py | 20 +++++++++++++------- tox.ini | 1 + 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/hendrics/efsearch.py b/hendrics/efsearch.py index 3818dc92..e82b87e3 100644 --- a/hendrics/efsearch.py +++ b/hendrics/efsearch.py @@ -148,9 +148,19 @@ def find_nearest_contour(cs, x, y, indices=None, pixel=True): if cs.filled: raise ValueError("Method does not support filled contours.") + from astropy.utils.introspection import minversion + import matplotlib as mpl - if indices is None: - indices = range(len(cs.collections)) + MATPLOTLIB_LT_3_8 = not minversion(mpl, "3.8.dev") + if MATPLOTLIB_LT_3_8: + paths_list = [] + trans_list = [] + for con in cs.collections: + trans_list.append(con.get_transform()) + paths_list.append(con.get_paths()) + else: + paths_list = [cs.get_paths()] + trans_list = [cs.get_transforms()] d2min = np.inf conmin = None @@ -161,11 +171,7 @@ def find_nearest_contour(cs, x, y, indices=None, pixel=True): point = np.array([x, y]) - for icon in indices: - con = cs.collections[icon] - trans = con.get_transform() - paths = con.get_paths() - + for icon, (paths, trans) in enumerate(zip(paths_list, trans_list)): for segNum, linepath in enumerate(paths): lc = linepath.vertices # transfer all data points to screen coordinates if desired diff --git a/tox.ini b/tox.ini index df65fa1c..02c5fbbe 100644 --- a/tox.ini +++ b/tox.ini @@ -50,6 +50,7 @@ deps = astropy5: astropy>=5.0.0,<6.0.0 oldestdeps: numpy<1.25 + oldestdeps: matplotlib<3.8 devdeps: numpy>=0.0.dev devdeps: scipy>=0.0.dev devdeps: matplotlib>=0.0.dev From a758aa2784345bb22c2edb7aa2b47755a77c7e5b Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 13:05:24 +0200 Subject: [PATCH 55/58] Fix syntax and add warning about API change --- hendrics/efsearch.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/hendrics/efsearch.py b/hendrics/efsearch.py index e82b87e3..5abbc211 100644 --- a/hendrics/efsearch.py +++ b/hendrics/efsearch.py @@ -26,6 +26,7 @@ from astropy import log from astropy.logger import AstropyUserWarning from astropy.table import Table +from astropy.utils.introspection import minversion from .base import ( HENDRICS_STAR_VALUE, @@ -55,6 +56,7 @@ ) try: + import matplotlib as mpl import matplotlib.pyplot as plt HAS_MPL = True @@ -113,9 +115,12 @@ def find_nearest_contour(cs, x, y, indices=None, pixel=True): ---------- x, y : float The reference point. + + Other Parameters + ---------------- indices : list of int or None, default: None Indices of contour levels to consider. If None (the default), all - levels are considered. + levels are considered. **This parameter is ignored since MPL 3.8** pixel : bool, default: True If *True*, measure distance in pixel (screen) space, which is useful for manual contour labeling; else, measure distance in axes @@ -148,8 +153,9 @@ def find_nearest_contour(cs, x, y, indices=None, pixel=True): if cs.filled: raise ValueError("Method does not support filled contours.") - from astropy.utils.introspection import minversion - import matplotlib as mpl + + if indices is not None: # pragma: no cover + warnings.warn("Since Matplotlib 3.8, indices are not usable anymore. Ignoring.") MATPLOTLIB_LT_3_8 = not minversion(mpl, "3.8.dev") if MATPLOTLIB_LT_3_8: From 94ca0dfb9e26c6ad9cbf7c633172a418e55056cb Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 14:00:25 +0200 Subject: [PATCH 56/58] Fix link to Adam's tutorial [docs only] --- hendrics/save_as_xspec.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hendrics/save_as_xspec.py b/hendrics/save_as_xspec.py index c5b4809a..c923ce44 100644 --- a/hendrics/save_as_xspec.py +++ b/hendrics/save_as_xspec.py @@ -24,8 +24,8 @@ def save_as_xspec(fname, direct_save=False, save_lags=True): Notes ----- - Uses method described here: - https://asd.gsfc.nasa.gov/XSPECwiki/fitting_timing_power_spectra_in_XSPEC + Uses method described by Ingram and Done in Appendix A of + `this paper__` """ ftype, contents = get_file_type(fname) From 6b014192919e0c3af8862814ec8960df5365c10e Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Tue, 22 Oct 2024 14:12:11 +0200 Subject: [PATCH 57/58] Update docs --- docs/index.rst | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 409f617d..b41d5c47 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -43,23 +43,34 @@ satellite (for sure XMM-Newton and RXTE). What's new ---------- -HENDRICS 8.0.0rc1 -~~~~~~~~~~~~~~~~~ +HENDRICS 8.1 +~~~~~~~~~~~~ + ++ Brings all bugfixes coming with `Stingray 2.2 `__ ++ New infrastructure, based on `pyproject.toml` as recommended by PEP 621 ++ More bug fixes: + + Fix issue with invalid coordinates + + Solved an issue with recent Numba versions + + Solved an issue with the initial values of TOA fitting + + Make analyze_qffa_results more flexible + + Fix bug when simulating by count rate in HENfake -+ Compatible with `Stingray 2.0.0rc1 `__, which introduced: +Older releases +~~~~~~~~~~~~~~ - + Lomb-Scargle periodograms and cross spectra are now available - + Power colors - + Easy filling of small gaps in light curves with random data - + Generic timeseries (complex data, multi-dimensional data) +.. collapse:: HENDRICS 8.0.0 -+ ``HENaccelsearch`` now has additional options for detrending, denoising and deorbiting -+ An improved Maximum likelihood algorithm as FFTFIT substitute for TOA calculation -+ NASA's IXPE added to supported missions -+ Better support of Stingray's native file formats + + Compatible with `Stingray 2.0.0 `__, which introduced: -Older releases -~~~~~~~~~~~~~~ + + Lomb-Scargle periodograms and cross spectra + + Power colors + + Easy filling of small gaps in light curves with random data + + Generic timeseries (complex data, multi-dimensional data) + + + ``HENaccelsearch`` now has additional options for detrending, denoising and deorbiting + + An improved Maximum likelihood algorithm as FFTFIT substitute for TOA calculation + + NASA's IXPE added to supported missions + + Better support of Stingray's native file formats .. collapse:: HENDRICS 7.0 From fc23cc2644173cac5ad5fd8e4bb02111ca37618c Mon Sep 17 00:00:00 2001 From: Matteo Bachetti Date: Mon, 2 Dec 2024 12:18:56 +0100 Subject: [PATCH 58/58] Update Stingray version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e5cdfe53..b64f7e16 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,7 @@ dependencies = [ "astropy>=4.0", "scipy>=1.1.0", "matplotlib>=3.0,!=3.4.00,!=3.8.0", - "stingray>=2.0.0", + "stingray>=2.2.3", "tqdm", "pyyaml" ]