Skip to content

Scaling functions ​

A ScalingFunction defines how the data of one system size are rescaled for given values of the parameters. The fit searches the parameters that make the rescaled curves of all sizes collapse.

Presets ​

Three presets cover the usual scaling forms (see Finite-size scaling for which observable needs which):

presetx is rescaled toy is rescaled to
:x  
:xy (default)   
:xny   

Error bars are rescaled like the y values. p_names gives the parameters meaningful names, which appear in the output of the problem:

julia
using ScalingCollapse

sf = ScalingFunction(:xny; p_names=["T_c", "nu", "gamma"])
sf.x_scale, sf.y_scale
("(x - T_c) * L^(1/nu)", "y * L^(-gamma/nu)")

As a shortcut, the keywords of the scaling function can be passed directly to ScalingProblem when no sf is given. Two names select the preset :x, three names :xy:

julia
ScalingProblem(xs, ys, Ls; p_names=["T_c", "nu"])  # same as sf=ScalingFunction(:x; p_names=["T_c", "nu"])

Fixing parameters ​

Pass a parameter's name and value to fix it:

julia
sf = ScalingFunction(:xy; p_names=["T_c", "nu", "beta"], nu=1.0)
ScalingCollapse.scaled_p_names(sf)
2-element Vector{String}:
 "T_c"
 "beta"

A fixed parameter is not fitted. p_space, starting_ps, optimal_ps and optimal_ps_error only contain the free parameters, in the order given by ScalingCollapse.scaled_p_names(sf). Fixing parameters works for presets and custom scaling functions alike, e.g. nu=1.0 for the 2D Ising model, see the Ising example.

The relative form ​

With relative=true, the presets rescale x relative to the critical point, as   , e.g. with the reduced temperature  :

julia
ScalingFunction(:x; p_names=["T_c", "nu"], relative=true).x_scale
"(x - T_c)/T_c * L^(1/nu)"

This was the default up to version 0.2. Both forms give the same parameters, but a window dx means different things: the window dx of the relative form is the window dx .* p1 of the absolute form. To reproduce an old fit, pass relative=true or multiply dx by the critical point. The absolute form also works for  .

Custom scaling functions ​

Any other scaling form is a function f(d, p1, p2, ...) that takes the data d::ScalingCollapse.Data of one system size and the values of all parameters (fixed ones included), and returns the rescaled data as a new ScalingCollapse.Data:

  • d.L is the system size, d.xs, d.ys, d.es are the x values, y values and errors;

  • return ScalingCollapse.Data(d.L, new_xs, new_ys, new_es) and do not modify d;

  • rescale the errors like the y values.

As an example, consider strong corrections to scaling: the order parameter of the synthetic data below follows    , with   and  , i.e. a 25% correction for  :

julia
using Random

x_c, ν, β, b, ω = 0.5, 1.2, 0.3, 2.0, 1.0
F(z) = 1 / (1 + exp(2z)) + 0.2
Ls = [8, 16, 32, 64]
xs = collect(range(0.2, 0.8; length=41))
rng = Xoshiro(7)
ys = [L^(-β / ν) * (1 + b * L^(-ω)) .* F.((xs .- x_c) .* L^(1 / ν)) .*
      (1 .+ 0.002 .* randn(rng, length(xs))) for L in Ls]

The preset :xy ignores the correction, and comes out several standard deviations too large:

julia
sp_preset = ScalingProblem(xs, ys, Ls;
    sf=ScalingFunction(:xy; p_names=["x_c", "nu", "beta"]),
    p_space=[0.4:0.01:0.6, 0.5:0.1:2.0, 0.0:0.05:0.6],
    dx=[-3.0, 3.0],
)
ScalingProblem
    Scaling function:
        x -> (x - x_c) * L^(1/nu)
        y -> y * L^(beta/nu)
    Optimal parameters:
        x_c = 0.5044776141090176 ± 0.004806636108938413
        nu = 1.1361378710806007 ± 0.11502561536412848
        beta = 0.41606139110150997 ± 0.02753302369347017
    Optimization interval dx:
        -3.0 < x < 3.0
    Searched parameter space:
        x_c ∈ 0.4:0.01:0.6
        nu ∈ 0.5:0.1:2.0
        beta ∈ 0.0:0.05:0.6

A custom scaling function divides the correction out. We fit its amplitude b and fix the correction exponent omega; x_scale and y_scale describe the scaling for the output:

julia
function corrected(d::ScalingCollapse.Data, x_c, nu, beta, b, omega)
    xs = @. (d.xs - x_c) * d.L^(1 / nu)
    c = d.L^(beta / nu) / (1 + b * d.L^(-omega))
    return ScalingCollapse.Data(d.L, xs, d.ys .* c, d.es .* c)
end

sf = ScalingFunction(corrected;
    p_names=["x_c", "nu", "beta", "b", "omega"],
    omega=1.0,
    x_scale="(x - x_c) * L^(1/nu)",
    y_scale="y * L^(beta/nu) / (1 + b * L^(-omega))",
)
sp_custom = ScalingProblem(xs, ys, Ls;
    sf,
    p_space=[0.4:0.02:0.6, 0.5:0.1:2.0, 0.0:0.05:0.6, 0.0:0.5:4.0],
    dx=[-3.0, 3.0],
)
ScalingProblem
    Scaling function:
        x -> (x - x_c) * L^(1/nu)
        y -> y * L^(beta/nu) / (1 + b * L^(-omega))
    Fixed parameters:
        omega = 1.0
    Optimal parameters:
        x_c = 0.5001223115185922 ± 0.0004916987402465885
        nu = 1.1987045985869602 ± 0.011128163233774288
        beta = 0.30059069700835167 ± 0.007694494515734365
        b = 1.9748774331229584 ± 0.13798714245552557
    Optimization interval dx:
        -3.0 < x < 3.0
    Searched parameter space:
        x_c ∈ 0.4:0.02:0.6
        nu ∈ 0.5:0.1:2.0
        beta ∈ 0.0:0.05:0.6
        b ∈ 0.0:0.5:4.0

All four free parameters agree with the true values. Every additional parameter makes the scan more expensive (here     grid points); with a good guess, starting_ps skips it, see Fitting.

Type stability

The scaling function is called many times during a fit. Broadcasting as above, or loops over preallocated vectors, keeps it fast. The parameters are passed as Float64.

Custom presets ​

To reuse a custom scaling form under a name, add a method to ScalingCollapse.handle_preset. It returns the function, the default parameter names and the display strings:

julia
function ScalingCollapse.handle_preset(::Val{:corrected}; kwargs...)
    p_names = get(kwargs, :p_names, ["x_c", "nu", "beta", "b", "omega"])
    x_scale = "(x - $(p_names[1])) * L^(1/$(p_names[2]))"
    y_scale = "y * L^($(p_names[3])/$(p_names[2])) / (1 + $(p_names[4]) * L^(-$(p_names[5])))"
    return corrected, p_names, x_scale, y_scale
end

sf = ScalingFunction(:corrected; omega=1.0)
sf.y_scale
"y * L^(beta/nu) / (1 + b * L^(-omega))"

The new preset accepts p_names and fixed parameters like the built-in ones.