Transforms API

Concise reference for all built-in transforms. For workflows, diagrams, and tuning guidance see the Transforms handbook and /user_guide/transforms.

FFTAnalysis

rheojax.transforms.fft_analysis.FFTAnalysis | Handbook: FFTAnalysis Convert time-domain data to frequency-domain spectra with optional detrending, windowing, and power spectral density output.

Parameters

Parameter (default)

Description

window ('hann')

Window function before FFT. Choices: 'hann', 'hamming', 'blackman', 'bartlett', 'none'.

detrend (True)

Remove linear trend before transforming.

return_psd (False)

Return power spectral density instead of magnitude.

normalize (True)

Normalize FFT amplitude by sample count.

class rheojax.transforms.fft_analysis.FFTAnalysis(window='hann', detrend=True, return_psd=False, normalize=True)[source]

Bases: BaseTransform

Transform time-domain rheological data to frequency domain using FFT.

This transform applies Fast Fourier Transform to convert time-domain signals to frequency domain, enabling analysis of characteristic frequencies, relaxation time distributions, and spectral features.

Features: - Multiple window functions (Hann, Hamming, Blackman, Bartlett) - Optional detrending to remove DC offset - Power spectral density (PSD) calculation - Peak detection for characteristic frequencies - JAX-accelerated computation

Parameters:
  • window (Literal['hann', 'hamming', 'blackman', 'bartlett', 'none']) – Window function to apply before FFT. Options: ‘hann’, ‘hamming’, ‘blackman’, ‘bartlett’, ‘none’

  • detrend (bool) – Whether to remove linear trend before FFT

  • return_psd (bool) – If True, return power spectral density instead of FFT magnitude

  • normalize (bool) – Whether to normalize the FFT result

Examples

>>> from rheojax.core.data import RheoData
>>> from rheojax.transforms.fft_analysis import FFTAnalysis
>>>
>>> # Create time-domain relaxation data
>>> t = jnp.linspace(0, 10, 1000)
>>> G_t = jnp.exp(-t/2.0)  # Exponential relaxation
>>> data = RheoData(x=t, y=G_t, domain='time')
>>>
>>> # Apply FFT analysis
>>> fft = FFTAnalysis(window='hann', detrend=True)
>>> freq_data = fft.transform(data)
>>>
>>> # freq_data.x contains frequencies, freq_data.y contains spectrum
__init__(window='hann', detrend=True, return_psd=False, normalize=True)[source]

Initialize FFT Analysis transform.

Parameters:
  • window (Literal['hann', 'hamming', 'blackman', 'bartlett', 'none']) – Window function to apply

  • detrend (bool) – Whether to detrend data before FFT

  • return_psd (bool) – Return power spectral density instead of magnitude

  • normalize (bool) – Normalize FFT output

find_peaks(freq_data, prominence=0.1, n_peaks=5)[source]

Find characteristic frequency peaks in FFT spectrum.

Parameters:
  • freq_data (RheoData) – Frequency-domain data from FFT

  • prominence (float) – Minimum prominence for peak detection (relative to max)

  • n_peaks (int) – Maximum number of peaks to return

Return type:

tuple[TypeAliasType, TypeAliasType]

Returns:

  • peak_freqs (JaxArray) – Frequencies of detected peaks

  • peak_heights (JaxArray) – Heights of detected peaks

get_characteristic_time(freq_data)[source]

Extract characteristic time from FFT peak frequency.

Parameters:

freq_data (RheoData) – Frequency-domain data from FFT

Returns:

Characteristic time (1 / peak_frequency)

Return type:

float

Mastercurve

rheojax.transforms.mastercurve.Mastercurve | Handbook: Mastercurve (Time-Temperature Superposition) Time-temperature superposition with WLF, Arrhenius, or manual shift factors plus optional vertical shifts and shift optimization.

Parameters

Parameter (default)

Description

reference_temp (298.15 K)

Target temperature in Kelvin for the mastercurve.

method ('wlf')

Shift factor model: 'wlf', 'arrhenius', or 'manual'.

C1 (17.44)

WLF constant \(C_1\).

C2 (51.6)

WLF constant \(C_2\) in Kelvin.

E_a (None)

Activation energy in J/mol for Arrhenius shifts (required when method='arrhenius').

vertical_shift (False)

Apply vertical (modulus) shifting in addition to horizontal shifts.

optimize_shifts (True)

Nonlinear least-squares refinement of supplied shift factors.

class rheojax.transforms.mastercurve.Mastercurve(reference_temp=298.15, method='wlf', C1=17.44, C2=51.6, E_a=None, vertical_shift=False, optimize_shifts=True, auto_shift=False)[source]

Bases: BaseTransform

Time-Temperature Superposition (TTS) mastercurve generation.

This transform applies time-temperature superposition to create mastercurves from multi-temperature rheological data. Supports both WLF and Arrhenius shift factor models for horizontal shifting, with optional vertical shifting, or automatic shift factor calculation via power-law intersection method.

The WLF equation is:

log(a_T) = -C1 * (T - T_ref) / (C2 + (T - T_ref))

The Arrhenius equation is:

log(a_T) = (E_a / R) * (1/T - 1/T_ref)

Automatic shift factors use power-law intersection (pyvisco algorithm):

Fits each curve to y = a*x^b + e, then computes shift from intersection

Parameters:
  • reference_temp (float) – Reference temperature in Kelvin

  • method (Literal['wlf', 'arrhenius', 'manual']) – Shift factor method: ‘wlf’, ‘arrhenius’, or ‘manual’

  • C1 (float) – WLF parameter C1 (universal value for polymers)

  • C2 (float) – WLF parameter C2 in Kelvin (universal value)

  • E_a (float | None) – Activation energy for Arrhenius (J/mol)

  • vertical_shift (bool) – Whether to apply vertical shifting (for modulus scaling)

  • optimize_shifts (bool) – Whether to optimize shift factors to minimize overlap error

  • auto_shift (bool) – Whether to use automatic shift factor calculation via power-law intersection. If True, overrides manual WLF/Arrhenius calculations.

Examples

>>> from rheojax.core.data import RheoData
>>> from rheojax.transforms.mastercurve import Mastercurve
>>>
>>> # Create multi-temperature frequency sweep data
>>> # (In practice, this would come from experimental measurements)
>>> temps = [273, 298, 323]  # K
>>> freq = jnp.logspace(-2, 2, 50)
>>> datasets = []
>>> for T in temps:
...     G_prime = some_modulus_function(freq, T)
...     data = RheoData(x=freq, y=G_prime, domain='frequency',
...                     metadata={'temperature': T})
...     datasets.append(data)
>>>
>>> # Create mastercurve at reference temperature (two equivalent APIs)
>>> mc = Mastercurve(reference_temp=298.15, method='wlf')
>>>
>>> # Option 1: Using create_mastercurve (explicit)
>>> mastercurve = mc.create_mastercurve(datasets)
>>>
>>> # Option 2: Using transform with list (returns shift factors too)
>>> mastercurve, shift_factors = mc.transform(datasets)
>>> print(shift_factors)  # {273.0: 42.5, 298.15: 1.0, 323.0: 0.024}
>>>
>>> # Option 3: Automatic shift factor calculation
>>> mc_auto = Mastercurve(reference_temp=298.15, auto_shift=True)
>>> mastercurve_auto, shifts_auto = mc_auto.transform(datasets)
__init__(reference_temp=298.15, method='wlf', C1=17.44, C2=51.6, E_a=None, vertical_shift=False, optimize_shifts=True, auto_shift=False)[source]

Initialize Mastercurve transform.

Parameters:
  • reference_temp (float) – Reference temperature in Kelvin

  • method (Literal['wlf', 'arrhenius', 'manual']) – Shift factor method

  • C1 (float) – WLF parameter C1

  • C2 (float) – WLF parameter C2 (Kelvin)

  • E_a (float | None) – Activation energy for Arrhenius (J/mol)

  • vertical_shift (bool) – Apply vertical shifting

  • optimize_shifts (bool) – Optimize shift factors

  • auto_shift (bool) – Use automatic power-law intersection for shift calculation

get_auto_shift_factors()[source]

Get automatic shift factors as arrays for plotting.

Return type:

tuple[ndarray, ndarray] | None

Returns:

  • temperatures (ndarray or None) – Array of temperatures in Kelvin, or None if not computed

  • log_aT (ndarray or None) – Array of log10 shift factors, or None if not computed

get_shift_factor(T)[source]

Get shift factor for a given temperature.

Parameters:

T (float) – Temperature in Kelvin

Returns:

Horizontal shift factor a_T

Return type:

float

set_manual_shifts(shift_factors)[source]

Set manual shift factors for each temperature.

Parameters:

shift_factors (dict[float, float]) – Dictionary mapping temperature (K) to shift factor

get_wlf_parameters()[source]

Get WLF parameters.

Returns:

Dictionary with keys ‘C1’, ‘C2’, and ‘T_ref’ (reference temperature)

Return type:

dict[str, float]

Raises:

ValueError – If method is not ‘wlf’

get_arrhenius_parameters()[source]

Get Arrhenius parameters.

Returns:

Dictionary with keys ‘E_a’ (activation energy) and ‘T_ref’ (reference temperature)

Return type:

dict[str, float]

Raises:

ValueError – If method is not ‘arrhenius’ or E_a is not set

get_shift_factors_array(temperatures=None)[source]

Get shift factors as arrays for plotting and analysis.

Parameters:

temperatures (list[float] | ndarray | None) – Temperatures in Kelvin. If None, uses temperatures from the last mastercurve creation (stored in shift_factors_).

Return type:

tuple[ndarray, ndarray]

Returns:

  • temperatures (ndarray) – Array of temperatures in Kelvin (sorted)

  • shift_factors (ndarray) – Array of shift factors corresponding to temperatures

Raises:

ValueError – If temperatures is None and no shift factors have been computed

Examples

>>> mc = Mastercurve(reference_temp=298.15, method='wlf')
>>> temps, shifts = mc.get_shift_factors_array([273.15, 298.15, 323.15])
>>> import matplotlib.pyplot as plt
>>> plt.plot(temps - 273.15, np.log10(shifts))
create_mastercurve(datasets, merge=True, return_shifts=False)[source]

Create mastercurve from multiple temperature datasets.

Parameters:
  • datasets (list[RheoData]) – List of datasets at different temperatures

  • merge (bool) – If True, merge all shifted data into single RheoData. If False, return list of shifted datasets.

  • return_shifts (bool) – If True, return tuple of (mastercurve, shift_factors). Only valid when merge=True.

Returns:

If merge=True and return_shifts=False: RheoData If merge=False: list of RheoData If merge=True and return_shifts=True: (RheoData, dict of shift factors)

Return type:

RheoData | list[RheoData] | tuple[RheoData, dict[float, float]]

Raises:

ValueError – If datasets don’t have temperature metadata or if return_shifts=True with merge=False

compute_overlap_error(datasets)[source]

Compute overlap error for multi-temperature data.

This metric quantifies how well the datasets collapse onto a mastercurve. Lower values indicate better superposition.

Parameters:

datasets (list[RheoData]) – List of datasets at different temperatures

Returns:

Overlap error (normalized RMSE in overlap regions)

Return type:

float

optimize_wlf_parameters(datasets, initial_C1=17.44, initial_C2=51.6)[source]

Optimize WLF parameters to minimize overlap error.

Parameters:
  • datasets (list[RheoData]) – Multi-temperature datasets

  • initial_C1 (float) – Initial guess for C1

  • initial_C2 (float) – Initial guess for C2

Return type:

tuple[float, float]

Returns:

  • C1_opt (float) – Optimized C1 parameter

  • C2_opt (float) – Optimized C2 parameter

Note

Uses scipy.optimize.minimize (Nelder-Mead) because the objective function compute_overlap_error() uses NumPy interpolation which is not JAX-traceable. This is acceptable per Technical Guidelines as it’s not in a hot path and is called only once during WLF parameter fitting.

MutationNumber

rheojax.transforms.mutation_number.MutationNumber | Handbook: MutationNumber Computes the mutation number \(\Delta\) from relaxation data to quantify viscoelastic character between perfectly elastic and perfectly viscous limits.

Parameters

Parameter (default)

Description

integration_method ('trapz')

Numerical integration strategy: 'trapz', 'simpson', or 'cumulative'.

extrapolate (False)

Estimate tail contributions beyond the measurement window.

extrapolation_model ('exponential')

Tail model when extrapolate=True. Options: 'exponential' or 'powerlaw'.

class rheojax.transforms.mutation_number.MutationNumber(integration_method='trapz', extrapolate=False, extrapolation_model='exponential')[source]

Bases: BaseTransform

Calculate mutation number from relaxation modulus data.

The mutation number (Δ) is a dimensionless parameter that quantifies how quickly a viscoelastic material relaxes. It is defined as:

Δ = ∫[0 to ∞] G(t) dt / (G(0) × τ_avg)

where: - G(t) is the relaxation modulus - G(0) is the initial modulus - τ_avg is the average relaxation time

The mutation number ranges from: - Δ → 0: Elastic solid (no relaxation) - Δ → 1: Viscous fluid (complete relaxation)

For practical calculations with finite time data:

Δ = ∫G(t)dt / (G(0) × τ_avg) where τ_avg = ∫G(t)dt / G(0)

This simplifies to:

Δ = [∫G(t)dt]² / [G(0) × ∫t×G(t)dt]

Parameters:
  • integration_method (Literal['trapz', 'simpson', 'cumulative']) – Numerical integration method: ‘trapz’, ‘simpson’, or ‘cumulative’

  • extrapolate (bool) – Whether to extrapolate to infinite time

  • extrapolation_model (str) – Model for extrapolation: ‘exponential’, ‘powerlaw’

Examples

>>> from rheojax.core.data import RheoData
>>> from rheojax.transforms.mutation_number import MutationNumber
>>>
>>> # Create relaxation data
>>> t = jnp.linspace(0, 100, 1000)
>>> G_t = 1000 * jnp.exp(-t/10.0)  # Exponential relaxation
>>> data = RheoData(x=t, y=G_t, domain='time',
...                 metadata={'test_mode': 'relaxation'})
>>>
>>> # Calculate mutation number
>>> mutation = MutationNumber(integration_method='trapz')
>>> delta = mutation.calculate(data)
>>> print(f"Mutation number: {delta:.4f}")
__init__(integration_method='trapz', extrapolate=False, extrapolation_model='exponential')[source]

Initialize Mutation Number transform.

Parameters:
  • integration_method (Literal['trapz', 'simpson', 'cumulative']) – Numerical integration method

  • extrapolate (bool) – Whether to extrapolate to infinite time

  • extrapolation_model (str) – Model for extrapolation

calculate(rheo_data)[source]

Calculate mutation number from relaxation data.

Parameters:

rheo_data (RheoData) – Relaxation modulus data

Returns:

Mutation number Δ

Return type:

float

Raises:

ValueError – If data is not relaxation mode

get_relaxation_time(rheo_data)[source]

Calculate average relaxation time from relaxation data.

Parameters:

rheo_data (RheoData) – Relaxation modulus data

Returns:

Average relaxation time τ_avg

Return type:

float

get_equilibrium_modulus(rheo_data)[source]

Estimate equilibrium modulus from long-time behavior.

Parameters:

rheo_data (RheoData) – Relaxation modulus data

Returns:

Equilibrium modulus G_eq (0 for viscous fluids)

Return type:

float

OWChirp

rheojax.transforms.owchirp.OWChirp | Handbook: OWChirp Optimal waveform chirp analysis for LAOS experiments, generating time-frequency maps, harmonic spectra, and nonlinear indicators.

Parameters

Parameter (default)

Description

n_frequencies (100)

Number of frequency bins used in the time-frequency analysis.

frequency_range ((1e-2, 1e2) Hz)

Minimum and maximum frequencies analyzed.

wavelet_width (5.0)

Width parameter controlling wavelet localization (higher = smoother).

extract_harmonics (True)

Whether to compute discrete harmonic amplitudes (G1, G3, …).

max_harmonic (7)

Highest harmonic order reported when extract_harmonics=True.

class rheojax.transforms.owchirp.OWChirp(n_frequencies=100, frequency_range=(0.01, 100.0), wavelet_width=5.0, extract_harmonics=True, max_harmonic=7)[source]

Bases: BaseTransform

Optimally Windowed Chirp transform for LAOS data analysis.

The OWChirp transform uses chirp wavelets to perform time-frequency analysis of Large Amplitude Oscillatory Shear (LAOS) data, extracting nonlinear viscoelastic parameters and higher harmonics.

This is particularly useful for: - Analyzing frequency-dependent nonlinear response - Extracting time-varying moduli during LAOS - Identifying structural changes during oscillatory deformation - Higher harmonic analysis (3rd, 5th, 7th harmonics)

The transform uses a Morlet-like chirp wavelet that is optimally windowed to balance time and frequency resolution.

Parameters:
  • n_frequencies (int) – Number of frequency points for analysis

  • frequency_range (tuple[float, float]) – Frequency range (f_min, f_max) in Hz

  • wavelet_width (float) – Width parameter for wavelet (controls time-frequency resolution)

  • extract_harmonics (bool) – Whether to extract higher harmonics (3ω, 5ω, etc.)

  • max_harmonic (int) – Maximum harmonic to extract (odd harmonics only)

Examples

Basic usage:

>>> from rheojax.core.data import RheoData
>>> from rheojax.transforms.owchirp import OWChirp
>>>
>>> # LAOS stress response data
>>> t = jnp.linspace(0, 100, 10000)
>>> omega = 1.0  # rad/s
>>> # Nonlinear stress: includes 3rd harmonic
>>> stress = jnp.sin(omega * t) + 0.2 * jnp.sin(3 * omega * t)
>>> data = RheoData(x=t, y=stress, domain='time',
...                 metadata={'test_mode': 'oscillation'})
>>>
>>> # Apply OWChirp transform
>>> owchirp = OWChirp(n_frequencies=50, extract_harmonics=True)
>>> spectrum = owchirp.transform(data)
>>>
>>> # Extract nonlinear parameters
>>> harmonics = owchirp.get_harmonics(data)
__init__(n_frequencies=100, frequency_range=(0.01, 100.0), wavelet_width=5.0, extract_harmonics=True, max_harmonic=7)[source]

Initialize OWChirp transform.

Parameters:
  • n_frequencies (int) – Number of frequency points

  • frequency_range (tuple[float, float]) – (f_min, f_max) in Hz

  • wavelet_width (float) – Wavelet width parameter

  • extract_harmonics (bool) – Extract higher harmonics

  • max_harmonic (int) – Maximum harmonic order

get_time_frequency_map(data)[source]

Get full time-frequency map (spectrogram).

Parameters:

data (RheoData) – Time-domain LAOS data

Return type:

tuple[Array, Array, Array]

Returns:

  • times (Array) – Time array

  • frequencies (Array) – Frequency array

  • coefficients (Array) – Complex wavelet coefficients (n_frequencies, n_times)

get_harmonics(data, fundamental_freq=None)[source]

Extract harmonic content from LAOS data.

Parameters:
  • data (RheoData) – Time-domain LAOS data

  • fundamental_freq (float | None) – Fundamental frequency in Hz. If None, auto-detect from FFT peak.

Returns:

Dictionary with harmonic amplitudes:

{'fundamental': (freq, amplitude),
 'third': (3*freq, amplitude),
 'fifth': (5*freq, amplitude),
 ...}

Return type:

dict

SmoothDerivative

rheojax.transforms.smooth_derivative.SmoothDerivative | Handbook: SmoothDerivative Noise-robust numerical differentiation with Savitzky-Golay, finite-difference, spline, or total-variation methods plus optional pre/post smoothing.

Parameters

Parameter (default)

Description

method ('savgol')

Differentiation algorithm: 'savgol', 'finite_diff', 'spline', 'total_variation'.

window_length (11)

Odd window size for Savitzky-Golay or smoothing kernels.

polyorder (3)

Polynomial order for Savitzky-Golay (must be < window_length).

deriv (1)

Derivative order to compute (>=1).

smooth_before (False)

Apply moving-average smoothing prior to differentiation.

smooth_after (False)

Apply smoothing to the derivative result.

smooth_window (5)

Window size for the optional smoothing passes.

class rheojax.transforms.smooth_derivative.SmoothDerivative(method='savgol', window_length=11, polyorder=3, deriv=1, smooth_before=False, smooth_after=False, smooth_window=5)[source]

Bases: BaseTransform

Smooth noise-robust numerical differentiation.

This transform computes derivatives of noisy rheological data using regularization techniques to suppress noise amplification. Multiple methods are available:

  1. Savitzky-Golay: Fits local polynomials and computes analytical derivatives

  2. Finite Difference: Simple finite differences with optional smoothing

  3. Spline: Fits smoothing splines and computes derivatives

  4. Total Variation: Regularized differentiation minimizing total variation

Savitzky-Golay is recommended for most applications as it preserves peak positions better than simple smoothing while providing good noise suppression.

Common use cases: - Creep compliance J(t) → relaxation modulus G(t) (via numerical inversion) - Storage modulus G’(ω) → loss modulus G”(ω) via Kramers-Kronig - Time-derivative of strain in controlled-strain experiments

Parameters:
  • method (Literal['savgol', 'finite_diff', 'spline', 'total_variation']) – Differentiation method

  • window_length (int) – Window length for Savitzky-Golay or smoothing (must be odd)

  • polyorder (int) – Polynomial order for Savitzky-Golay (must be < window_length)

  • deriv (int) – Order of derivative (1, 2, 3, …)

  • smooth_before (bool) – Apply additional smoothing before differentiation

  • smooth_after (bool) – Apply additional smoothing after differentiation

Examples

>>> from rheojax.core.data import RheoData
>>> from rheojax.transforms.smooth_derivative import SmoothDerivative
>>>
>>> # Create noisy creep compliance data
>>> t = jnp.linspace(0.1, 10, 100)
>>> J_t = t + 0.1 * jnp.random.normal(size=len(t))  # Noisy linear creep
>>> data = RheoData(x=t, y=J_t, domain='time')
>>>
>>> # Compute smooth derivative
>>> deriv = SmoothDerivative(window_length=11, polyorder=3)
>>> dJ_dt = deriv.transform(data)
>>>
>>> # For higher-order derivatives
>>> deriv2 = SmoothDerivative(window_length=15, polyorder=4, deriv=2)
>>> d2J_dt2 = deriv2.transform(data)
__init__(method='savgol', window_length=11, polyorder=3, deriv=1, smooth_before=False, smooth_after=False, smooth_window=5)[source]

Initialize Smooth Derivative transform.

Parameters:
  • method (Literal['savgol', 'finite_diff', 'spline', 'total_variation']) – Differentiation method

  • window_length (int) – Window length (must be odd)

  • polyorder (int) – Polynomial order for Savitzky-Golay

  • deriv (int) – Derivative order

  • smooth_before (bool) – Smooth before differentiation

  • smooth_after (bool) – Smooth after differentiation

  • smooth_window (int) – Smoothing window size

estimate_noise_level(data)[source]

Estimate noise level in data.

This uses the median absolute deviation (MAD) of the second derivative as a robust noise estimator.

Parameters:

data (RheoData) – Input data

Returns:

Estimated noise standard deviation

Return type:

float

SRFS (Strain-Rate Frequency Superposition)

rheojax.transforms.srfs.SRFS | Handbook: Strain-Rate Frequency Superposition (SRFS) Collapses flow curves at different shear rates onto a master curve, analogous to time-temperature superposition but in the shear rate domain.

Parameters

Parameter (default)

Description

reference_gamma_dot (1.0)

Reference shear rate for the master curve.

auto_shift (False)

Automatically compute optimal shift factors using SGR power-law theory.

class rheojax.transforms.srfs.SRFS(reference_gamma_dot=1.0, auto_shift=False)[source]

Bases: BaseTransform

Strain-Rate Frequency Superposition (SRFS) transform.

SRFS collapses flow curves measured at different shear rates onto a master curve by applying horizontal shift factors. This is analogous to time-temperature superposition (TTS) but uses shear rate rather than temperature.

For SGR (Soft Glassy Rheology) materials, the shift factor follows:

a(gamma_dot) = (gamma_dot / gamma_dot_ref)^m

where m = (2 - x) and x is the noise temperature.

Parameters:
  • reference_gamma_dot (float) – Reference shear rate for the master curve (1/s)

  • auto_shift (bool) – If True, automatically compute optimal shift factors from data overlap

reference_gamma_dot

Reference shear rate

Type:

float

shift_factors_

Computed shift factors after transform

Type:

dict[float, float] or None

Examples

>>> from rheojax.transforms.srfs import SRFS
>>> from rheojax.core.data import RheoData
>>>
>>> # Create flow curve datasets at different reference shear rates
>>> datasets = [
...     RheoData(x=gamma_dots_1, y=eta_1, metadata={'reference_gamma_dot': 0.1}),
...     RheoData(x=gamma_dots_2, y=eta_2, metadata={'reference_gamma_dot': 1.0}),
...     RheoData(x=gamma_dots_3, y=eta_3, metadata={'reference_gamma_dot': 10.0}),
... ]
>>>
>>> # Create SRFS transform
>>> srfs = SRFS(reference_gamma_dot=1.0)
>>>
>>> # Apply SRFS shift (requires SGR parameters)
>>> mastercurve, shift_factors = srfs.transform(datasets, x=1.5, tau0=1e-3)

Notes

  • Shift factors depend on SGR noise temperature x

  • For x < 1 (glass), shift behavior changes near yield stress

  • For x >= 2 (Newtonian), shift factor approaches 1

__init__(reference_gamma_dot=1.0, auto_shift=False)[source]

Initialize SRFS transform.

Parameters:
  • reference_gamma_dot (float) – Reference shear rate for the master curve

  • auto_shift (bool) – Whether to automatically compute optimal shift factors

compute_shift_factor(gamma_dot, x, tau0)[source]

Compute SRFS shift factor from SGR theory.

For SGR materials, the shift factor follows a power-law:

a(gamma_dot) = (gamma_dot / gamma_dot_ref)^m

where m = (2 - x) for the power-law fluid regime (1 < x < 2).

Parameters:
  • gamma_dot (float) – Shear rate to compute shift for (1/s)

  • x (float) – SGR noise temperature (dimensionless)

  • tau0 (float) – SGR attempt time (s)

Returns:

Shift factor a(gamma_dot)

Return type:

float

Notes

  • For x = 1.5, exponent m = 0.5

  • For x = 2 (Newtonian), m = 0, shift factor = 1

  • For x < 1 (glass), behavior near yield stress is different

transform(data, x=None, tau0=None, return_shifts=False)[source]

Apply SRFS transformation (public interface).

Parameters:
  • data (RheoData | list[RheoData]) – Single dataset or list of datasets to transform

  • x (float | None) – SGR noise temperature

  • tau0 (float | None) – SGR attempt time

  • return_shifts (bool) – If True, return shift factors dict along with mastercurve

Returns:

Transformed data, optionally with shift factors

Return type:

RheoData | list[RheoData] | tuple[RheoData, dict[float, float]]

create_mastercurve(datasets, x, tau0, merge=True, return_shifts=False)[source]

Create SRFS master curve from multiple flow curve datasets.

Parameters:
  • datasets (list[RheoData]) – Flow curves at different reference shear rates

  • x (float) – SGR noise temperature

  • tau0 (float) – SGR attempt time

  • merge (bool) – If True, merge all shifted data into single RheoData

  • return_shifts (bool) – If True, return shift factors dict with mastercurve

Returns:

Master curve or list of shifted datasets, optionally with shifts

Return type:

RheoData | list[RheoData] | tuple[RheoData, dict[float, float]]

get_shift_factors_array(gamma_dots=None, x=None, tau0=None)[source]

Get shift factors as arrays for plotting.

Parameters:
  • gamma_dots (list[float] | ndarray | None) – Shear rates to compute shifts for. If None, uses stored values.

  • x (float | None) – SGR noise temperature (required if computing new shifts)

  • tau0 (float | None) – SGR attempt time (required if computing new shifts)

Return type:

tuple[ndarray, ndarray]

Returns:

  • gamma_dots (ndarray) – Array of shear rates (sorted)

  • shift_factors (ndarray) – Array of corresponding shift factors

SPP Decomposer

rheojax.transforms.spp_decomposer.SPPDecomposer | Full API: SPP Analysis API Time-domain LAOS decomposition into cage modulus, yield stresses, power-law flow, and nonlinearity metrics using the Sequence of Physical Processes framework.

class rheojax.transforms.spp_decomposer.SPPDecomposer(omega, gamma_0, n_harmonics=39, yield_tolerance=0.02, start_cycle=0, end_cycle=None, use_numerical_method=False, step_size=8, num_mode=2, wrap_strain_rate=True)[source]

Bases: BaseTransform

SPP decomposition transform for LAOS stress analysis.

Applies the Sequence of Physical Processes (SPP) framework to decompose LAOS stress signals and extract nonlinear viscoelastic parameters.

The transform requires oscillatory shear data with known frequency and strain amplitude. It computes:

  1. Elastic/viscous stress decomposition

  2. Yield stress extraction (static and dynamic)

  3. Power-law flow parameters

  4. Lissajous-Bowditch metrics

  5. Harmonic decomposition

Parameters:
  • omega (float) – Angular frequency ω (rad/s) of the oscillation

  • gamma_0 (float) – Strain amplitude γ_0 (dimensionless)

  • n_harmonics (int) – Number of odd harmonics to extract for stress (default: 39 per MATLAB SPPplus)

  • yield_tolerance (float) – Fractional tolerance for yield point detection (default: 0.02)

  • start_cycle (int) – First cycle to analyze (0-indexed). Use to skip startup transients. Default: 0 (start from beginning).

  • end_cycle (int | None) – Last cycle to analyze (exclusive). None means use all available cycles. Default: None.

  • use_numerical_method (bool) – If True, use MATLAB-compatible numerical differentiation for raw data. If False (default), use Fourier-based decomposition.

  • step_size (int) – Step size k for numerical differentiation (only used if use_numerical_method=True). Default: 8 to mirror SPPplus v2.1.

  • num_mode (int) – Numerical differentiation mode (1 = edge-aware, 2 = periodic/looped), matching SPPplus num_mode. Only used when use_numerical_method=True.

omega

Angular frequency

Type:

float

gamma_0

Strain amplitude

Type:

float

gamma_dot_0

Strain rate amplitude (ω * γ_0)

Type:

float

n_harmonics

Number of harmonics for decomposition

Type:

int

start_cycle

First cycle to analyze

Type:

int

end_cycle

Last cycle to analyze

Type:

int or None

use_numerical_method

Whether using numerical differentiation

Type:

bool

results_

Dictionary of computed SPP metrics (after transform)

Type:

dict

Examples

Basic usage with RheoData:

>>> from rheojax.core.data import RheoData
>>> from rheojax.transforms.spp_decomposer import SPPDecomposer
>>>
>>> # LAOS stress-strain data
>>> omega = 1.0  # rad/s
>>> gamma_0 = 1.0  # strain amplitude
>>> t = jnp.linspace(0, 2*jnp.pi, 1000)
>>> strain = gamma_0 * jnp.sin(omega * t)
>>> stress = 100.0 * strain + 20.0 * jnp.sin(3 * omega * t)  # With 3rd harmonic
>>>
>>> data = RheoData(
...     x=t,
...     y=stress,
...     domain='time',
...     metadata={
...         'test_mode': 'oscillation',
...         'omega': omega,
...         'gamma_0': gamma_0,
...         'strain': strain,
...     }
... )
>>>
>>> # Apply SPP decomposition
>>> decomposer = SPPDecomposer(omega=omega, gamma_0=gamma_0)
>>> result = decomposer.transform(data)
>>>
>>> # Access metrics
>>> print(f"Static yield stress: {decomposer.results_['sigma_sy']:.2f} Pa")
>>> print(f"Dynamic yield stress: {decomposer.results_['sigma_dy']:.2f} Pa")

Notes

  • Input data must be time-domain stress signal

  • Strain data must be available in metadata[‘strain’] or computed from ω, γ_0

  • Output includes both decomposed waveforms and extracted parameters

__init__(omega, gamma_0, n_harmonics=39, yield_tolerance=0.02, start_cycle=0, end_cycle=None, use_numerical_method=False, step_size=8, num_mode=2, wrap_strain_rate=True)[source]

Initialize SPP decomposer transform.

Parameters:
  • omega (float) – Angular frequency (rad/s)

  • gamma_0 (float) – Strain amplitude (dimensionless)

  • n_harmonics (int) – Number of odd harmonics to extract (default: 39)

  • yield_tolerance (float) – Tolerance for yield point detection (default: 0.02)

  • start_cycle (int) – First cycle to analyze, 0-indexed (default: 0)

  • end_cycle (int | None) – Last cycle to analyze, exclusive (default: None, use all)

  • use_numerical_method (bool) – Use MATLAB-compatible numerical differentiation (default: False)

  • step_size (int) – Step size k for numerical differentiation (default: 8)

  • num_mode (int) – Numerical differentiation mode (1=edge-aware, 2=periodic). Default: 2.

  • wrap_strain_rate (bool) – If True, infer strain rate with periodic wrapping when missing (default: True)

get_results()[source]

Get computed SPP analysis results.

Returns:

Dictionary containing all SPP metrics: - sigma_sy: Static yield stress (Pa) - sigma_dy: Dynamic yield stress (Pa) - K: Consistency index (Pa·s^n) - n_power_law: Power-law exponent - harmonic_amplitudes: Array of harmonic amplitudes - harmonic_phases: Array of harmonic phases - I3_I1_ratio: Third harmonic nonlinearity ratio - G_L, G_M: Large and minimum strain moduli (Pa) - eta_L, eta_M: Large and minimum rate viscosities (Pa·s) - S_factor: Stiffening ratio - T_factor: Thickening ratio - G_cage: Time-resolved cage modulus (array) - sigma_elastic: Elastic stress contribution (array) - sigma_viscous: Viscous stress contribution (array)

Return type:

dict

Raises:

RuntimeError – If transform has not been applied yet

Examples

>>> decomposer = SPPDecomposer(omega=1.0, gamma_0=1.0)
>>> _ = decomposer.transform(data)
>>> results = decomposer.get_results()
>>> print(f"I3/I1 = {results['I3_I1_ratio']:.4f}")
get_yield_stresses()[source]

Get static and dynamic yield stresses.

Returns:

(sigma_sy, sigma_dy) in Pa

Return type:

tuple[float, float]

Raises:

RuntimeError – If transform has not been applied yet

get_nonlinearity_metrics()[source]

Get nonlinearity quantification metrics.

Returns:

Dictionary with: - I3_I1_ratio: Third harmonic ratio (FT-rheology) - S_factor: Strain stiffening ratio - T_factor: Shear thickening ratio

Return type:

dict

Raises:

RuntimeError – If transform has not been applied yet

__repr__()[source]

String representation of transform.

Return type:

str