Fitting & Analysis
This module implements:
- Shift factor computation and WLF fitting (
build_shift_factors!) - Master curve construction (
build_master_curve) - Kramers-Kronig verification (
build_Kramers_Kronig!) - Global model identification (
fit2S2P1D,fit1S2P1D,fitHS) - Model evaluation helpers (
eval_model,eval_array)
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— ADataSerieswith at least two temperatures.Tref— Reference temperature (°C). Does not have to be ind.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.
ViscoAnalysis.build_master_curve — Function
build_master_curve(d::DataSeries, field, Tref; index_freq=1)
-> (ω_reduced, values)Shift all isothermal sweeps onto a single master curve at Tref.
Arguments
d—DataSeries.field— Key to extract from each temperature entry, e.g."M*","|M*|","delta".Tref— Reference temperature (°C).index_freq— Frequency index used internally bybuild_shift_factors!.
Returns
(ω_reduced, values) — both sorted by reduced angular frequency.
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.
Model identification
ViscoAnalysis.fit2S2P1D — Function
fit2S2P1D(d, Tref; index_freq=1) -> FitResult2S2P1DIdentify 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 HzViscoAnalysis.fit1S2P1D — Function
fit1S2P1D(d, Tref; index_freq=1) -> FitResult1S2P1DIdentify 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)ViscoAnalysis.fitHS — Function
fitHS(d, Tref; index_freq=1) -> FitResultHSIdentify 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)Model evaluation
ViscoAnalysis.eval_model — Function
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.
ViscoAnalysis.eval_array — Function
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).
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.
| Fitter | Optimiser | Max evals | Parameters |
|---|---|---|---|
fit2S2P1D | NLopt :LN_SBPLX | 100 000 | E∞, E₀, δ, τ, k, h, β |
fit1S2P1D | NLopt :LN_NELDERMEAD | 500 000 | E₀, δ, τ, k, h, β |
fitHS | NLopt :LN_NELDERMEAD | 500 000 | E∞, E₀, δ, τ, k, h |
The constraint $k < h$ is enforced for all models.
FitResult fields
FitResult2S2P1D
| Field | Description |
|---|---|
Einf | $E_\infty$ — glassy modulus [MPa] |
E0 | $E_0$ — static modulus [MPa] |
delta | $\delta$ — shape parameter |
tauE | $\tau_E$ — relaxation time [s] |
k | low-frequency exponent |
h | high-frequency exponent |
beta | $\beta$ — dashpot coefficient |
residual | final value of the objective function J |
model | callable 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)