Skip to main content

neidspec

neidspec provides a spectrum class and supporting utilities for reduced NEID Level 2 spectra. It is the low-level spectrum dependency used by NEIDSpecMatch.

Installation

Use Python 3.10, 3.11, or 3.12:

python -m pip install neidspec

Version 0.2 uses a tested pure-NumPy cross-correlation implementation. The legacy crosscorr package and its Fortran/numpy.distutils build are no longer required.

Validation boundary

Version 0.2 validates the NEID Level 2 reader, DRP metadata/DQ handling, order mapping, deblazing, resampling, dynamic rotational broadening, and the numerical structure of explicit custom-mask CCF fits. These checks do not by themselves validate a stellar-parameter scale, a particular line mask, or compatibility between different DRP reductions. Publication-facing parameter inference must add a matched reference-library validation product, as NEIDSpecMatch does in its strict mode.

Historical general-purpose modules such as spec_help, stats_help, priors, and plotting helpers remain importable for compatibility but are outside this release's publication-validation boundary. The unrelated HPF-only CreateTemplate helper was removed and must not be used to construct a NEIDSpecMatch reference library.

Reading a spectrum

from neidspec import NEIDSpectrum

with NEIDSpectrum("neidL2_YYYYMMDDThhmmss.fits") as spectrum:
    print(spectrum.drp_version, spectrum.bjd, spectrum.berv)
    flux, error = spectrum.resample_order(wavelength_grid, order=102)

The default behavior is deliberately tied to the NEID DRP product:

  • Inputs must identify themselves as NEID science, Level 2, high-resolution products (INSTRUME=NEID, OBSTYPE=Sci, DATALVL=2, OBS-MODE=HR); other or ambiguous products are rejected.
  • DQLEVEL1 and DQLEVEL2 are interpreted using the DRP-defined low two assessment bits. Pass (0) is accepted; warning (1) is accepted with a Python warning and marked unvalidated; fail (2) and reserved/invalid (3) are rejected. Missing flags in older products are warned and unvalidated. Use require_dq_pass=True to reject warning or missing assessments. Higher diagnostic bits are preserved and do not by themselves fail an exposure.
  • BJD_TDB and barycentric velocity are read from per-order SSBJDnnn and SSBRVnnn header values. They are not recomputed.
  • Science and sky flux are deblazed with the corresponding Level 2 SCIBLAZE and SKYBLAZE HDUs. Variance is propagated through the same division.
  • The stellar rest-frame shift uses the Level 2 weighted CCFRVMOD value only after checking that it is finite, interior to the stored CCF grid, and consistent with CCFRVSUM. This is structural validation, not proof that the DRP RV is astrophysically correct. A failed check raises an actionable error; it never silently substitutes a generic-mask CCF.
  • Reading a spectrum performs no TIC/SIMBAD query and writes no target cache.
  • Default unit telluric/sky error factors do not read external line masks. Non-unit mask inflation requires an explicit user-supplied mask path; legacy masks with unresolved redistribution rights are not included in artifacts. Where telluric and sky masks overlap, the larger factor is applied once (a union), rather than multiplying the two factors.
  • spectrum.drp_version, data_level, observing_mode, observatory, and provenance retain reduction metadata for downstream products.

An old external instrument-response file can still be used for controlled comparisons, but it is never selected implicitly:

spectrum = NEIDSpectrum(
    filename,
    blaze_source="legacy_response",
    legacy_response_path="/path/to/response.fits",
)

Optional error inflation around a reviewed external mask is explicit as well:

spectrum = NEIDSpectrum(
    filename,
    tell_err_factor=2.0,
    telluric_mask_path="/path/to/telluric-mask.txt",
)

An explicitly supplied RV takes precedence over the DRP value:

spectrum = NEIDSpectrum(filename, rv=-12.345)

For a custom binary-mask measurement, both the intent and mask must be explicit (rv_source="custom_ccf", ccf_mask_path=...). Because NEID L2 wavelengths are vacuum wavelengths, an unregistered mask must also declare ccf_mask_medium="air" or "vacuum". The exact bundled ESO ESPRESSO M3 bytes (SHA-256 a3ef5906...bed3) have a checksum-bound air policy and are converted to vacuum before correlation. A renamed byte-for-byte copy is still recognized by its digest; a modified file is unregistered and needs an explicit declaration. This avoids the roughly 83 km/s zero-point error produced by correlating those air coordinates directly against a NEID vacuum grid. The bundled mask remains available for reproducibility tests only, and no science-facing method selects or validates it as a general NEID mask. Direct calculate_ccf_for_orders and rvabs_for_orders calls therefore require an explicit mask_path or a provenance-bearing Mask object; use mask_wavelength_medium for an unregistered path. Custom-mask fits use bounded parameters, reject edge/degenerate fits and inconsistent order RVs, and record the mask SHA-256, input and CCF wavelength media, conversion policy, and per-order diagnostics. These numerical checks do not validate whether the mask is astrophysically appropriate for the target.

For direct Mask construction, the legacy use_airtovac=True or False keyword remains accepted as an explicit medium declaration. Omitting both that keyword and wavelength_medium is accepted only for a checksum-registered mask; it now raises for an unregistered file rather than silently assuming vacuum. An explicit declaration that conflicts with a registered digest also raises.

NEIDSpecList accepts either a scalar RV or one value per input file. Use None for files that should use their validated DRP RV, and a catalog value for spectra whose DRP CCF diagnostics fail:

with NEIDSpecList(filelist=files, rv=[None, -0.7434, None]) as spectra:
    ...

Lists created from filelist own and close their spectra. A caller-supplied splist is borrowed and is not closed unless take_ownership=True is explicit. NEIDSpecList.resample_order(..., order=102) uses the same absolute DRP array-row order convention as NEIDSpectrum.resample_order and forwards resampling options such as return_mask and max_gap_factor to every member.

Resampling and rotational broadening

resample_order propagates diagonal variance with squared linear-interpolation weights and never interpolates across a bad pixel, non-finite wavelength, or a gap larger than max_gap_factor times the typical source spacing. Unsupported output pixels are NaN; request the mask with return_mask=True. Interpolation makes neighboring outputs correlated, especially on an oversampled grid. The covariance is not returned, and this limitation plus the oversampling ratio are recorded in spectrum.last_resample_provenance.

Rotational broadening uses a dynamically sized, complete kernel on a uniform log-wavelength grid. vsini=0 is an exact identity. A half-kernel at every order edge or masked gap is trimmed to NaN so edge lines are never reflected or extrapolated into a fit. Optimizers must freeze a common pixel set at their maximum allowed rotation using neidspec.rotbroad_help.broadening_valid_mask; otherwise the valid-pixel count would change with trial vsini. broaden_variance applies squared weights at each stage as a diagonal approximation; intermediate covariance is omitted and the result must not be treated as an independent-pixel likelihood.

Order identifiers

NEID arrays contain 122 rows. Array row 0 corresponds to physical echelle order 173, and row 121 corresponds to echelle order 52. NEIDSpecMatch's familiar orders 55 and 102 are array-row indices, not echelle numbers.

from neidspec import order_index_to_echelle

assert order_index_to_echelle(55) == 118

OrderMap is used throughout the package to translate requested DRP row indices into sliced in-memory arrays and to construct order-specific header keywords. Out-of-range requests raise an explicit error.

Reproducibility guidance

Record spectrum.drp_version with derived results. Do not combine spectra or reference libraries reduced with different NEID DRP minor versions without a specific validation. neidspec records the version; it does not silently declare mixed reductions scientifically equivalent.

Optional target resolution

NEIDSpectrum(..., resolve_target=True) retains the legacy catalog-resolution convenience and may query remote services. It is not needed for NEID barycentric metadata. Generic barycentric recomputation through Target requires an observatory to be supplied explicitly. Named aliases are restricted to NEID, KPNO, WIYN, and WIYN 3.5m, using coordinates recorded in NEID Level 2 headers; other sites must provide latitude, longitude, and elevation explicitly, and unknown names raise instead of falling back to geocentric coordinates. No McDonald Observatory or APO default remains. Catalog RVs retained by Target in km/s are converted to the m/s units required by barycorrpy.

Tests

The regression suite uses only synthetic FITS fixtures:

python -m unittest discover -s tests -v

Third-party algorithm attribution is recorded in THIRD_PARTY_NOTICES.md.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

neidspec-0.2.1.tar.gz (331.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

neidspec-0.2.1-py3-none-any.whl (156.6 kB view details)

Uploaded Python 3

File details

Details for the file neidspec-0.2.1.tar.gz.

File metadata

  • Download URL: neidspec-0.2.1.tar.gz
  • Upload date:
  • Size: 331.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for neidspec-0.2.1.tar.gz
Algorithm Hash digest
SHA256 b88446ed399d26415cb48f807eb7f858c550913c6003beb74a7e3e5f01001519
MD5 dab0459e855dc2c7200a213424042f6b
BLAKE2b-256 73b748df9a9b88d982002451cbfbd9b6ab81b4f242966826e0719feb9b6dd309

See more details on using hashes here.

Provenance

The following attestation bundles were made for neidspec-0.2.1.tar.gz:

Publisher: release.yml on TeHanHunter/neidspec

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file neidspec-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: neidspec-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 156.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for neidspec-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 49870277ce28a87ec91cb9b4af1b4d057bebea57945219daefde3ae0938e9ae3
MD5 ffa30d61de1540f903c18376ce855531
BLAKE2b-256 6a902199c284affc563cf886766875c4579b5b92e941804fb7b4f256306ad4fe

See more details on using hashes here.

Provenance

The following attestation bundles were made for neidspec-0.2.1-py3-none-any.whl:

Publisher: release.yml on TeHanHunter/neidspec

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 files

0.2.0

2 files

0.1.0

2 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page