Fitting & Analysis

This module implements:


Shift factors and master curve

ViscoAnalysis.build_shift_factors!Function
build_shift_factors!(d::DataSeries, Tref; index_freq=1) -> Vector{Float64}

Compute log₁₀(aT) shift factors relative to Tref for every temperature in d.list_temp and fit a WLF law. The fitted WLF function and coefficients are stored in d.wlf, d.C1, d.C2.

Arguments

  • d — A DataSeries with at least two temperatures.
  • Tref — Reference temperature (°C). Does not have to be in d.list_temp; the WLF is re-referenced if needed.
  • index_freq — Index into the frequency vector used to compute incremental shift steps (default: 1, i.e. the first frequency).

Returns

Vector of log₁₀(aT) values aligned with d.list_temp.

source
ViscoAnalysis.build_master_curveFunction
build_master_curve(d::DataSeries, field, Tref; index_freq=1)
    -> (ω_reduced, values)

Shift all isothermal sweeps onto a single master curve at Tref.

Arguments

  • dDataSeries.
  • field — Key to extract from each temperature entry, e.g. "M*", "|M*|", "delta".
  • Tref — Reference temperature (°C).
  • index_freq — Frequency index used internally by build_shift_factors!.

Returns

(ω_reduced, values) — both sorted by reduced angular frequency.

source
ViscoAnalysis.build_Kramers_Kronig!Function
build_Kramers_Kronig!(d::DataSeries)

Compute the Kramers-Kronig (BT2) verification data for every temperature entry in d and store the results in-place:

  • d[T]["delta/90"] — δ/90 (normalised phase angle).
  • d[T]["dlog|M*|/dlogomega"] — d log|E*| / d log ω (numerical derivative).
  • d[T]["Erreur K.K."] — Relative error between the two quantities.
source

Model identification

ViscoAnalysis.fit2S2P1DFunction
fit2S2P1D(d, Tref; index_freq=1) -> FitResult2S2P1D

Identify 2S2P1D parameters (E∞, E₀, δ, τ, k, h, β) on the complex master curve at Tref using NLopt :LN_SBPLX (up to 100 000 evaluations).

r = fit2S2P1D(series[1], 10.0)
println(r)
r(2π * 10.0)    # E* at 10 Hz
source
ViscoAnalysis.fit1S2P1DFunction
fit1S2P1D(d, Tref; index_freq=1) -> FitResult1S2P1D

Identify 1S2P1D parameters (E₀, δ, τ, k, h, β) on the complex master curve at Tref using NLopt :LN_NELDERMEAD (up to 500 000 evaluations).

The 1S2P1D model has no glassy branch (E∞ is implicit): E*(p) = E₀ / (1 + δ(pτ)^{-k} + (pτ)^{-h} + 1/(pβτ))

r = fit1S2P1D(series[1], 10.0)
println(r)
source
ViscoAnalysis.fitHSFunction
fitHS(d, Tref; index_freq=1) -> FitResultHS

Identify Huet-Sayegh parameters (E∞, E₀, δ, τ, k, h) on the complex master curve at Tref using NLopt :LN_NELDERMEAD (up to 500 000 evaluations).

The Huet-Sayegh model has no dashpot (β → ∞): E*(p) = E∞ + (E₀ - E∞) / (1 + δ(pτ)^{-k} + (pτ)^{-h})

r = fitHS(series[1], 10.0)
println(r)
source

Model evaluation

ViscoAnalysis.eval_modelFunction
eval_model(model_func, ω; rtd=180/π) -> (re, im, absval, deg)

Evaluate a complex-modulus function at each frequency in ω (rad/s) and return real part, imaginary part, magnitude, and phase in degrees.

source
ViscoAnalysis.eval_arrayFunction
eval_array(G_arr; rtd=180/π) -> (re, im, absval, deg)

Decompose a pre-computed vector of complex modulus values into real, imaginary, magnitude, and phase (degrees).

source

Optimisation details

All three fitters minimise the same frequency-weighted least-squares objective over the complex master curve:

\[J = \sum_k \Delta\log\omega_k \left|1 - \frac{E^*(\omega_k)}{E^*_{\text{exp}}(\omega_k)}\right|^2\]

The $\Delta\log\omega_k$ weight is computed as half the log-frequency spacing to adjacent points, so that every frequency decade contributes equally regardless of sampling density.

FitterOptimiserMax evalsParameters
fit2S2P1DNLopt :LN_SBPLX100 000E∞, E₀, δ, τ, k, h, β
fit1S2P1DNLopt :LN_NELDERMEAD500 000E₀, δ, τ, k, h, β
fitHSNLopt :LN_NELDERMEAD500 000E∞, E₀, δ, τ, k, h

The constraint $k < h$ is enforced for all models.


FitResult fields

FitResult2S2P1D

FieldDescription
Einf$E_\infty$ — glassy modulus [MPa]
E0$E_0$ — static modulus [MPa]
delta$\delta$ — shape parameter
tauE$\tau_E$ — relaxation time [s]
klow-frequency exponent
hhigh-frequency exponent
beta$\beta$ — dashpot coefficient
residualfinal value of the objective function J
modelcallable E*(p) function

FitResult1S2P1D

Same as above except no Einf field (6 parameters total).

FitResultHS

Same as FitResult2S2P1D except no beta field (6 parameters total).


Usage examples

Full pipeline

using ViscoAnalysis

series = load_data("data.xlsx"; MPa=true)
d = series[1]

# Compute shift factors and WLF
loga = build_shift_factors!(d, 10.0)
println("C1 = $(d.C1),  C2 = $(d.C2)")

# Build the complex master curve
ω_red, E_complex = build_master_curve(d, "M*", 10.0)

# Fit the 2S2P1D model
r = fit2S2P1D(d, 10.0)
println(r)

# Evaluate the model over a frequency range
ω_range = 10 .^ range(-4, 4, length=200) .* 2π
re, im_part, absval, deg = eval_model(r.model, ω_range)

Kramers-Kronig check

build_Kramers_Kronig!(d)
entry = d[10.0]
println("KK error at T=10°C: ", entry["Erreur K.K."])

Evaluate a pre-computed array

E_arr = [r(ω) for ω in ω_range]   # Vector{Complex}
re, im_part, absval, deg = eval_array(E_arr)