PronyConversion

Overview

The rheojax.transforms.PronyConversion transform converts between time-domain and frequency-domain viscoelastic data using the Prony series decomposition. The Prony series is the discrete analog of the continuous relaxation spectrum and provides exact analytical relations between \(G(t)\), \(G'(\omega)\), and \(G''(\omega)\).

Key Capabilities:

  • Time → frequency conversion: \(G(t) \to G'(\omega), G''(\omega)\) via Prony fitting

  • Frequency → time conversion: \(G'(\omega), G''(\omega) \to G(t)\) via inverse Prony

  • Automatic mode selection: Number of modes auto-selected based on data density

  • JAX-accelerated evaluation: JIT-compiled Prony summations for fast evaluation

Unlike the FFTAnalysis approach (which is non-parametric), Prony conversion produces a compact parametric representation that can be evaluated at arbitrary output points and naturally integrates with LVEEnvelope and multi-mode model families.

Comparison with FFT and OWChirp

All three transforms can convert time-domain data to frequency-domain, but they are fundamentally different tools designed for different use cases:

Domain Conversion Transforms Compared

Aspect

PronyConversion

FFT Analysis

OWChirp

Method

Parametric model fitting (NNLS)

Non-parametric signal processing (DFT)

Wavelet-based time-frequency analysis

Input

\(G(t)\) or \(G'(\omega), G''(\omega)\) (material functions)

Raw time-domain signal \(x(t)\) (stress, strain waveforms)

LAOS waveform \(\sigma(t)\) (periodic oscillatory)

Output

\(G^*(\omega)\) or \(G(t)\) + Prony parameters \((G_i, \tau_i)\)

Frequency spectrum, PSD, harmonic amplitudes

Time-frequency map + harmonic content vs time

Frequency grid

Arbitrary (evaluate Prony at any \(\omega\))

Fixed by sampling rate (\(\Delta f = f_s/N\))

Adaptive (wavelet resolution varies with frequency)

Key output

Compact parameters for downstream use (LVE envelope, model initialization)

Spectral magnitude and phase

Time-resolved nonlinear indicators (\(I_3/I_1\) vs time)

Assumes

Linear viscoelasticity (superposition of exponentials)

Uniform sampling, stationarity

Periodic LAOS excitation

Reversible

Yes (bidirectional: time ↔ freq)

Yes (via inverse FFT)

No (analysis only, not synthesis)

When to use which:

  • PronyConversion: You have \(G(t)\) or \(G^*(\omega)\) and need the other domain representation, or you need Prony parameters for LVEEnvelope / ../models/gmm/generalized_maxwell. Best for material functions measured under standard protocols (relaxation, frequency sweep).

  • FFT Analysis: You have raw time-domain waveforms (stress/strain records) and need to extract the frequency content. Best for signal processing—detecting harmonics, computing PSD, Kramers-Kronig checks. Does not produce Prony parameters.

  • OWChirp: You have LAOS data and need time-resolved frequency analysis (how does nonlinearity evolve within the deformation cycle or across cycles). Best for chirp experiments, curing/gelation monitoring, or tracking structural changes.

They complement, not overlap. A typical multi-step workflow might chain them:

  1. OWChirp → extract \(G'(\omega)\), \(G''(\omega)\) from chirp experiment

  2. PronyConversion → fit Prony series to the extracted \(G^*(\omega)\)

  3. LVEEnvelope → predict startup stress from the Prony parameters

Or: FFT → convert \(G(t)\) to \(G^*(\omega)\)SpectrumInversion → recover \(H(\tau)\).

Mathematical Theory

Prony Series Representation

The Prony series (generalized Maxwell model) expresses the relaxation modulus as a sum of decaying exponentials:

\[G(t) = G_e + \sum_{i=1}^{N} G_i \exp(-t / \tau_i)\]

where:

  • \(G_e\) is the equilibrium modulus (\(G_e = 0\) for liquids, \(G_e > 0\) for solids)

  • \(G_i\) are the mode strengths (Pa)

  • \(\tau_i\) are the relaxation times (s)

  • \(N\) is the number of modes

Analytical Frequency-Domain Relations

Substituting the Prony series into the Boltzmann superposition integral yields closed-form expressions for the dynamic moduli:

Storage modulus (elastic component):

\[G'(\omega) = G_e + \sum_{i=1}^{N} G_i \frac{\omega^2 \tau_i^2}{1 + \omega^2 \tau_i^2}\]

Loss modulus (viscous component):

\[G''(\omega) = \sum_{i=1}^{N} G_i \frac{\omega \tau_i}{1 + \omega^2 \tau_i^2}\]

Each mode contributes a Debye relaxation peak to \(G''(\omega)\) centered at \(\omega = 1/\tau_i\).

Key properties:

  • \(G'(\omega \to 0) = G_e\) (equilibrium modulus)

  • \(G'(\omega \to \infty) = G_e + \sum G_i\) (glassy modulus)

  • \(G''\) peak for mode \(i\) occurs at \(\omega_{\text{peak}} = 1/\tau_i\) with height \(G_i / 2\)

Fitting Procedure

Time-domain fitting (\(G(t) \to\) Prony parameters):

  1. Log-space the relaxation times: \(\tau_i\) from \(t_{\min}\) to \(t_{\max}\)

  2. Estimate \(G_e = G(t_{\max})\) (long-time plateau)

  3. Build kernel matrix \(A_{ji} = \exp(-t_j / \tau_i)\)

  4. Solve non-negative least squares (NNLS): \(\min_{\mathbf{G} \ge 0} \|A \mathbf{G} - (G(t) - G_e)\|^2\)

Frequency-domain fitting (\(G'(\omega), G''(\omega) \to\) Prony parameters):

  1. Log-space \(\tau_i\) from \(1/\omega_{\max}\) to \(1/\omega_{\min}\)

  2. Estimate \(G_e = \min(G')\)

  3. Build stacked kernel:

    \[\begin{split}A = \begin{bmatrix} \omega^2 \tau^2 / (1 + \omega^2 \tau^2) \\ \omega \tau / (1 + \omega^2 \tau^2) \end{bmatrix}\end{split}\]
  4. Solve NNLS jointly on \([G' - G_e, \; G'']\)

NNLS guarantees \(G_i \ge 0\), ensuring thermodynamic consistency (positive relaxation spectrum).

Parameters

PronyConversion Parameters

Parameter

Type

Default

Description

n_modes

int | None

None

Number of Prony modes. If None, auto-selected as max(3, min(N_data // 5, 20)).

direction

str

"time_to_freq"

Conversion direction: "time_to_freq" or "freq_to_time".

omega_out

ndarray | None

None

Target frequency array for time→freq. Auto-generated if None.

t_out

ndarray | None

None

Target time array for freq→time. Auto-generated if None.

Parameter Selection Guidelines

Number of modes:

  • 3–5 modes: Single-relaxation materials (dilute solutions, simple gels)

  • 8–12 modes: Moderate complexity (polymer melts, concentrated solutions)

  • 15–20 modes: Broad spectra (blends, filled systems, multi-component)

  • Auto-select: Safe default—uses N_data // 5 capped at 20

Direction choice:

  • "time_to_freq": Start from stress relaxation \(G(t)\) data

  • "freq_to_time": Start from frequency sweep \(G'(\omega)\), \(G''(\omega)\) data

Input / Output Specifications

Time → Frequency:

  • Input: RheoData with x = time (s), y = \(G(t)\) (Pa)

  • Output: RheoData with x = \(\omega\) (rad/s), y = \(G^* = G' + iG''\) (Pa)

Frequency → Time:

  • Input: RheoData with x = \(\omega\) (rad/s), y = complex \(G^*\) or (N, 2) array \([G', G'']\)

  • Output: RheoData with x = time (s), y = \(G(t)\) (Pa)

The metadata dict includes a PronyResult with G_i, tau_i, G_e, and n_modes.

Usage

Time-Domain to Frequency-Domain

from rheojax.transforms import PronyConversion
from rheojax.core.data import RheoData
import numpy as np

# Stress relaxation data
t = np.logspace(-2, 2, 200)
G_t = 1e4 * np.exp(-t / 0.5) + 500 * np.exp(-t / 10.0)

data = RheoData(x=t, y=G_t, metadata={'test_mode': 'relaxation'})

# Convert to frequency domain
prony = PronyConversion(n_modes=10, direction="time_to_freq")
freq_data, info = prony.transform(data)

omega = freq_data.x
G_star = freq_data.y  # Complex: G' + iG''
G_prime = G_star.real
G_double_prime = G_star.imag

# Access Prony parameters
result = info["prony_result"]
print(f"Modes: {result.n_modes}, G_e: {result.G_e:.1f} Pa")

Frequency-Domain to Time-Domain

from rheojax.transforms import PronyConversion
import numpy as np

# Oscillatory data (frequency sweep)
omega = np.logspace(-2, 2, 50)
G_prime = 1e4 * omega**2 / (1 + omega**2)
G_double_prime = 1e4 * omega / (1 + omega**2)
G_star = G_prime + 1j * G_double_prime

osc_data = RheoData(x=omega, y=G_star, metadata={'test_mode': 'oscillation'})

# Convert to time domain
prony = PronyConversion(direction="freq_to_time", n_modes=8)
relax_data, info = prony.transform(osc_data)

t = relax_data.x
G_t = relax_data.y  # Relaxation modulus G(t)

Integration with LVE Envelope

from rheojax.transforms import PronyConversion, LVEEnvelope

# Step 1: Fit Prony series to relaxation data
prony = PronyConversion(n_modes=10, direction="time_to_freq")
_, info = prony.transform(relaxation_data)
result = info["prony_result"]

# Step 2: Compute startup stress envelope from Prony parameters
lve = LVEEnvelope(
    shear_rate=0.1,
    G_i=result.G_i,
    tau_i=result.tau_i,
    G_e=result.G_e,
)
envelope_data, _ = lve.transform()

# Compare with experimental startup data
import matplotlib.pyplot as plt
plt.loglog(envelope_data.x, envelope_data.y, '--', label='LVE envelope')
plt.loglog(startup_data.x, startup_data.y, 'o', label='Experiment')
plt.xlabel('Time (s)')
plt.ylabel('Stress (Pa)')
plt.legend()

Pipeline Integration

from rheojax.pipeline import Pipeline
from rheojax.transforms import PronyConversion
from rheojax.models import FractionalMaxwellGel

pipe = Pipeline()
pipe.load(relaxation_data)
pipe.transform(PronyConversion(n_modes=12, direction="time_to_freq"))
pipe.fit(FractionalMaxwellGel(), test_mode='oscillation')
pipe.plot()

Validation and Quality Control

Assessing Fit Quality

R² metric: Compare reconstructed data with original:

# Round-trip validation: G(t) → Prony → G'(ω) → Prony → G(t)
prony_fwd = PronyConversion(n_modes=12, direction="time_to_freq")
freq_data, info1 = prony_fwd.transform(relaxation_data)

prony_inv = PronyConversion(n_modes=12, direction="freq_to_time",
                             t_out=relaxation_data.x)
recon_data, info2 = prony_inv.transform(freq_data)

# Compare
ss_res = np.sum((relaxation_data.y - recon_data.y)**2)
ss_tot = np.sum((relaxation_data.y - np.mean(relaxation_data.y))**2)
R2 = 1 - ss_res / ss_tot
print(f"Round-trip R² = {R2:.6f}")

Mode convergence: Increase n_modes until output stabilizes.

Common Failure Modes

1. Overfitting (too many modes):

  • Symptom: Oscillatory artifacts in reconstructed data, spurious peaks in \(G''\)

  • Fix: Reduce n_modes, or use SpectrumInversion with regularization

2. Underfitting (too few modes):

  • Symptom: Poor fit at short or long times, missing features

  • Fix: Increase n_modes, verify data spans sufficient decades

3. Negative G_e estimate:

  • Symptom: Warning about negative target values

  • Cause: Data does not reach equilibrium, or \(G(t_{\max})\) underestimated

  • Fix: Extend measurement time, or manually set G_e=0

See Also

  • SpectrumInversion — Continuous spectrum \(H(\tau)\) via regularization (complementary to discrete Prony representation)

  • LVEEnvelope — Uses Prony parameters to compute startup stress envelope

  • FFTAnalysis — Non-parametric time↔frequency conversion

  • Maxwell (Classical) — Single Maxwell element (1-mode Prony)

  • ../models/gmm/generalized_maxwell — Multi-mode generalized Maxwell (N-mode Prony)

API References

  • Module: rheojax.transforms

  • Class: rheojax.transforms.PronyConversion

References

  1. Ferry, J.D. (1980). Viscoelastic Properties of Polymers, 3rd ed. Wiley. Chapter 3: Exact interconversions via Prony series.

  2. Tschoegl, N.W. (1989). The Phenomenological Theory of Linear Viscoelastic Behavior: An Introduction. Springer-Verlag. DOI: 10.1007/978-3-642-73602-5

  3. Baumgaertel, M. & Winter, H.H. (1989). “Determination of discrete relaxation and retardation time spectra from dynamic mechanical data.” Rheol. Acta, 28, 511–519. DOI: 10.1007/BF01332922

  4. Honerkamp, J. & Weese, J. (1993). “A nonlinear regularization method for the calculation of relaxation spectra.” Rheol. Acta, 32, 65–73. DOI: 10.1007/BF00396678