# ExoJAX Spectral Operator (Sop) Class: Rotation, Instrumental Broadening, and Photometry

> Explore the ExoJAX Spectral Operator (Sop) class for unified spectral processing including rotation, instrumental broadening, and photometry. Learn how to apply these effects efficiently using FFT or Overlap-and-Add.

- Repository: [Hajime Kawahara/exojax](https://github.com/hajimekawahara/exojax)
- Tags: deep-dive
- Published: 2026-03-03

---

**The ExoJAX Spectral Operator (Sop) classes provide a unified interface for applying rotational broadening, Gaussian instrumental profiles, resampling, and photometric integration to synthetic spectra, all implemented in [`src/exojax/postproc/specop.py`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/postproc/specop.py) with support for both FFT and Overlap-and-Add convolution backends.**

The ExoJAX library (hajimekawahara/exojax) includes a powerful post-processing toolkit called **Spectral Operators** (Sop) that transforms high-resolution synthetic spectra into realistic observables. These classes handle everything from stellar rotation to spectrograph resolution and photometric filter integration, inheriting shared infrastructure for velocity grids and convolution backends.

## Core Architecture of the Spectral Operator Classes

All spectral operators derive from a common base that standardizes how ExoJAX prepares convolution kernels and selects computational backends.

### The SopCommonConv Base Class

The `SopCommonConv` class in [`src/exojax/postproc/specop.py`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/postproc/specop.py) supplies the shared infrastructure for any convolution-type transformation. During initialization, it calculates the spectral resolution using `grid_resolution("ESLOG", self.nu_grid)` and builds a velocity grid via `velocity_grid` (lines 177–190). The class stores the maximum velocity (`vrmax`) and constructs the velocity array (`self.vrarray`) used for Doppler-shift calculations.

Key methods include `generate_vrarray` for grid construction and `check_ola_reducible`, which verifies whether a spectrum can be split evenly for the Overlap-and-Add (OLA) backend. The constructor also records the chosen `convolution_method`, selecting between standard FFT-based convolution or OLA for very long spectra.

## Rotational Broadening with SopRotation

The `SopRotation` class applies **rigid rotation broadening** (projected rotation speed `vsini`) with support for quadratic limb darkening.

### Rigid Rotation Implementation

The `rigid_rotation` method receives a raw spectrum, the projected rotation speed `vsini` (in km s⁻¹), and limb-darkening coefficients `u1` and `u2`. According to the source code (lines 205–240), this method forwards the call to either `exojax.postproc.spin_rotation.convolve_rigid_rotation` (FFT backend) or `convolve_rigid_rotation_ola` (OLA backend), depending on the `convolution_method` selected at instantiation. The velocity grid encodes the Doppler shift for each velocity element, while the limb-darkening law is applied inside the low-level routine.

```python
from exojax.postproc.specop import SopRotation

# nu_grid: wavenumber axis (cm⁻¹)

# spectrum: 1‑D flux array on the same grid

rot = SopRotation(nu_grid, vsini_max=150.0, convolution_method="exojax.signal.convolve")

# Apply 30 km s⁻¹ rotation with linear limb darkening (u1=0.6, u2=0.0)

broadened = rot.rigid_rotation(spectrum, vsini=30.0, u1=0.6, u2=0.0)

```

## Instrumental Broadening and Resampling with SopInstProfile

The `SopInstProfile` class handles **instrumental broadening** via Gaussian convolution and subsequent resampling onto arbitrary instrument grids.

### Gaussian Instrumental Profiles

The `ipgauss` method (lines 244–274) convolves the spectrum with a Gaussian instrumental profile characterized by `standard_deviation` in km s⁻¹. Internally, this converts the sigma value to a Gaussian kernel on the velocity grid. The method calls either `exojax.postproc.response.ipgauss` (FFT) or `ipgauss_ola` (OLA) based on the backend configuration.

### Spectral Resampling and RV Shifts

The `sampling` method interpolates the broadened spectrum onto a user-provided wavenumber grid and applies a radial-velocity shift. As implemented in lines 276–289, this delegates to `exojax.postproc.response.sampling`, accepting `radial_velocity` in km s⁻¹ and a target `nu_grid_sampling` array.

```python
from exojax.postproc.specop import SopInstProfile

inst = SopInstProfile(nu_grid, vrmax=200.0, convolution_method="exojax.signal.ola")

# Apply Gaussian IP with σ = 5 km s⁻¹ using OLA backend

ip_spectrum = inst.ipgauss(spectrum, standard_deviation=5.0)

# Resample onto instrument grid with 10 km s⁻¹ radial velocity shift

final_spectrum = inst.sampling(ip_spectrum, radial_velocity=10.0,
                               nu_grid_sampling=instrument_grid)

```

## Photometric Integration with SopPhoto

The `SopPhoto` class provides **photometric integration** over filter response curves to compute apparent magnitudes. Unlike the convolution operators, this class loads a filter curve (e.g., "2MASS/2MASS.Ks"), interpolates it onto the high-resolution wavenumber grid, and evaluates the apparent magnitude using `exojax.utils.photometry.apparent_magnitude`. It includes utilities for downloading filter data automatically when `download=True`.

```python
from exojax.postproc.specop import SopPhoto

# Initialize for 2MASS Ks filter

photo = SopPhoto("2MASS/2MASS.Ks", download=True)

# Compute apparent magnitude

mag = photo.apparent_magnitude(spectrum)
print(f"Ks magnitude = {mag:.3f}")

```

## Convolution Backends: FFT vs Overlap-and-Add

The **Spectral Operator** architecture supports two convolution backends selected via the `convolution_method` parameter. The standard `exojax.signal.convolve` uses FFT-based methods suitable for most spectra, while `exojax.signal.ola` implements the Overlap-and-Add algorithm optimized for very long spectra that exceed memory constraints. The `check_ola_reducible` helper verifies that the spectrum length and kernel size permit efficient OLA segmentation.

## Summary

- The **Spectral Operator** classes in [`src/exojax/postproc/specop.py`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/postproc/specop.py) provide a unified API for post-processing synthetic spectra in ExoJAX.
- `SopRotation` applies rigid rotation broadening with limb-darkening coefficients `u1` and `u2` using either FFT or OLA backends.
- `SopInstProfile` combines Gaussian instrumental broadening (`ipgauss`) with resampling and radial-velocity shifts (`sampling`).
- `SopPhoto` integrates spectra over photometric filter responses to calculate apparent magnitudes.
- All convolution operators inherit velocity-grid logic and backend selection from `SopCommonConv`, ensuring consistent resolution and performance characteristics.

## Frequently Asked Questions

### What is the difference between the FFT and OLA convolution backends in ExoJAX?

The FFT backend (`exojax.signal.convolve`) performs standard Fourier-domain convolution suitable for moderate-length spectra. The OLA backend (`exojax.signal.ola`) uses the Overlap-and-Add algorithm to process very long spectra in segments, reducing memory usage while maintaining accuracy. You select the backend via the `convolution_method` parameter when instantiating any Sop class.

### How does SopRotation handle limb darkening?

The `SopRotation.rigid_rotation` method accepts limb-darkening coefficients `u1` and `u2` corresponding to the quadratic limb-darkening law. These parameters are passed to the underlying convolution routines in [`src/exojax/postproc/spin_rotation.py`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/postproc/spin_rotation.py), which apply the rotational kernel weighted by the limb-darkening profile before convolving with the spectrum.

### Can SopInstProfile resample to arbitrary wavelength grids?

Yes. The `SopInstProfile.sampling` method accepts any arbitrary wavenumber grid via the `nu_grid_sampling` parameter. It interpolates the internally computed spectrum onto this grid using `exojax.postproc.response.sampling`, optionally applying a radial-velocity shift to account for target motion.

### Does SopPhoto support custom filter curves?

Yes. While `SopPhoto` includes built-in support for standard filters like 2MASS via the SVO Filter Profile Service, you can instantiate it with any valid filter identifier string. The class downloads the filter transmission curve, interpolates it onto your spectrum's wavenumber grid, and computes the integrated magnitude using the `apparent_magnitude` utility in [`src/exojax/utils/photometry.py`](https://github.com/hajimekawahara/exojax/blob/main/src/exojax/utils/photometry.py).