Skip to content

CEM II/B-V and CEM II/B-M (V-LL), with their CEM I, integrated in time ​

Before this page

Validation against measured blended pastes, the same four pastes at the extents De Weerdt et al. (2011) measured, and CEM I 52.5 R with slag, fly ash and limestone, integrated in time, the same path on another blend.

De Weerdt et al. (2011) blended a clinker interground with gypsum with 5 % limestone powder, 35 % siliceous fly ash, or 30 % fly ash and 5 % limestone, and followed the pastes at w/b = 0.5 and 20 °C for six months by X-ray diffraction: the clinker phases left, and the portlandite and the ettringite formed (their Table 7). The validation page computes these pastes at the degrees of reaction they measured. Here the clinker reacts under a rate law, and only the fly ash follows the measurement: what the pastes form over six months is then a prediction of the law and of the thermodynamics together, which nothing below was fitted to.

1. The laws ​

The materials are the templates of the validation page: the clinker by its Rietveld phases and its minor oxides, the fly ash by its crystals, inert, and its glass, the limestone by its calcite. Each clinker phase dissolves under the law of Parrott and Killoh (1984) with the parameters Lavergne et al. (2018) tabulate, at the Blaine fineness of the cement ((De Weerdt et al., 2011; Table 1)) and at the water/clinker ratio of the paste. The glass of the fly ash reacts as De Weerdt et al. (2011) measured it by image analysis: the fit printed on their Fig. 7, in percent of the fly ash at t days,

julia
using ChemistryLab, DynamicQuantities, OptimaSolver, Printf, Plots
include(joinpath(pkgdir(ChemistryLab), "scripts", "deweerdt2011_kinetics.jl"))

a, b, c = dw11_value("fly_ash_fit_a"), dw11_value("fly_ash_fit_b"), dw11_value("fly_ash_fit_c")
@printf("y = %g + %g ln(t + %g)\n", a, b, c)
y = -15 + 10 ln(t + 4.5)

written on the degree of reaction α of the glass rather than on the time, as the Waller law (Waller, 1999) is: with s the glass's share of the fly ash, y = 100 s α, t + c = exp((y − a)/b), and the rate is dα/dt = b exp(−(y − a)/b) / (100 s) per day (dw11k_fly_ash_law). The limestone, the gypsum and everything else are at equilibrium.

ASSUMED: the minor oxides of the clinker (free lime, the alkalis, magnesia and the sulfate of the clinker itself) enter the equilibrium at the mixing. The validation page releases them with the clinker as a whole.

2. The four pastes ​

julia
setup = dw11k_setup()
day = 86400.0
# `Any`: the type of a run is long enough that a dictionary specialized on it
# takes minutes to compile.
runs = Dict{String, Any}(mix => dw11k_run(setup, mix) for mix in DW11_MIXES)
for mix in DW11_MIXES
    @printf("%-9s %s, %3d steps\n", mix, runs[mix].sol.retcode, length(runs[mix].sol.t))
end
OPC       Success, 161 steps
OPC-L     Success, 162 steps
OPC-FA    Success, 147 steps
OPC-FA-L  Success, 142 steps

Neither law reads the equilibrium partition, so the trajectory does not depend on it: every number below is computed on the certified replay of each run (speciated_states), in percent of the solids of the paste, every solid with its water and the unreacted part of the binder included.

3. The clinker phases ​

julia
days = [1, 7, 28, 90, 180]
states = Dict{String, Any}(mix => dw11k_replay(runs[mix], days) for mix in DW11_MIXES)
contents = Dict(mix => dw11k_contents(runs[mix], states[mix]) for mix in DW11_MIXES)
cell(mix, k, d, q) = (m = dw11_phase_content(mix, d, q); m === nothing ?
    @sprintf("%5.1f/  – ", contents[mix][k][q]) : @sprintf("%5.1f/%4.1f", contents[mix][k][q], m))
for mix in ("OPC", "OPC-FA")
    println(mix, ", wt.% computed/measured")
    println("  days     C3S        C2S        C3A        C4AF     OPC reacted")
    for (k, d) in enumerate(days)
        println(lpad(d, 6), "  ", join((cell(mix, k, d, q) for q in ("C3S", "C2S", "C3A", "C4AF", "opc_reacted")), "  "))
    end
end
OPC, wt.% computed/measured
  days     C3S        C2S        C3A        C4AF     OPC reacted
     1   25.3/15.3   13.6/17.8    5.4/ 5.9    5.2/ 5.9   44.2/51.7
     7   11.8/ 6.5    8.9/17.1    2.4/ 2.5    2.7/ 3.7   70.9/68.0
    28    9.0/ 4.5    6.3/15.5    1.8/ 1.5    1.7/ 2.5   78.8/74.3
    90    7.4/ 2.0    4.7/ 8.2    1.5/ 1.5    1.4/ 2.5   83.1/84.7
   180    6.7/ 1.4    4.1/ 6.5    1.3/ 1.5    1.2/ 2.7   84.9/87.1
OPC-FA, wt.% computed/measured
  days     C3S        C2S        C3A        C4AF     OPC reacted
     1   17.2/ 9.2    9.2/12.2    3.6/ 3.8    3.6/ 4.0   41.7/49.1
     7    7.6/ 2.4    6.2/11.6    1.6/ 0.8    1.9/ 2.5   70.0/69.8
    28    4.1/  –     4.4/10.6    0.8/  –     1.1/ 1.6   81.9/79.0
    90    2.4/  –     3.2/ 7.8    0.5/  –     0.7/ 1.5   88.1/84.0
   180    1.8/  –     2.7/ 7.1    0.3/  –     0.5/  –    90.7/87.6
julia
meas(mix, d, q) = something(dw11_phase_content(mix, d, q), NaN)
function phase_panel(mix, quantities; title = mix, legend = false, data = contents)
    p = plot(; xscale = :log10, xlabel = "age (days)", ylabel = "wt.% of the solids", title, titlefontsize = 10, legend)
    for (k, q) in enumerate(quantities)
        plot!(p, days, [data[mix][j][q] for j in eachindex(days)]; lw = 2, color = k, marker = :circle, ms = 3, label = q)
        scatter!(p, days, [meas(mix, d, q) for d in days]; color = k, marker = :diamond, label = "")
    end
    # The diamonds take the color of their phase; the legend names them once.
    legend === false || scatter!(p, [NaN], [NaN]; color = :black, marker = :diamond, label = "measured (XRD)")
    return p
end
plot(phase_panel("OPC", ("C3S", "C2S", "C3A", "C4AF"); legend = :topright, title = "OPC, w/b 0.5, 20 °C"),
     phase_panel("OPC-FA", ("C3S", "C2S", "C3A", "C4AF"));
     layout = (1, 2), size = (900, 380), left_margin = 6Plots.mm, bottom_margin = 6Plots.mm)

The last column is the table's own measure of the clinker reacted: one minus the sum of the four phases over that sum at the mixing, the same for the model and for the measurement.

4. Portlandite and ettringite ​

julia
for mix in DW11_MIXES
    println(mix, ", wt.% computed/measured")
    println("  days   portlandite   ettringite")
    for (k, d) in enumerate(days)
        println(lpad(d, 6), "     ", join((cell(mix, k, d, q) for q in ("portlandite", "ettringite")), "    "))
    end
end
OPC, wt.% computed/measured
  days   portlandite   ettringite
     1      11.1/12.6     12.2/ 9.8
     7      17.7/18.9      9.6/10.1
    28      19.1/19.0      7.3/ 9.1
    90      19.8/21.8      6.3/ 7.4
   180      20.1/21.9      5.9/ 8.8
OPC-L, wt.% computed/measured
  days   portlandite   ettringite
     1      10.5/11.5     11.7/ 9.0
     7      17.1/18.0     12.0/ 9.6
    28      18.4/18.3     11.7/10.4
    90      19.1/18.8     11.6/ 9.9
   180      19.4/21.0     11.5/11.0
OPC-FA, wt.% computed/measured
  days   portlandite   ettringite
     1       6.8/ 8.7      8.5/ 9.0
     7       9.2/14.0      4.5/ 7.4
    28       7.3/13.7      0.0/ 7.5
    90       4.3/12.5      0.0/ 6.6
   180       2.5/11.3      0.0/ 6.6
OPC-FA-L, wt.% computed/measured
  days   portlandite   ettringite
     1       6.9/ 8.8      8.5/ 9.3
     7       9.6/13.5      8.7/ 9.2
    28       8.3/12.8      8.5/ 9.5
    90       6.2/12.2      8.3/10.5
   180       4.7/10.8      8.3/10.9
julia
plot([phase_panel(mix, ("portlandite", "ettringite"); legend = mix == first(DW11_MIXES) ? :topleft : false,
                  title = mix == first(DW11_MIXES) ? "$mix, w/b 0.5, 20 °C" : mix) for mix in DW11_MIXES]...;
     layout = (1, 4), size = (1100, 330), left_margin = 6Plots.mm, bottom_margin = 7Plots.mm)

Where the aluminum and the sulfate are at six months, in mmol per 100 g of binder:

julia
phases = ("ettringite", "monosulphate12", "C4AH13", "monocarbonate", "hemicarbonate",
          "straetlingite", "C3AH6", "hydrotalcite")
println(rpad("", 16), join((lpad(mix, 10) for mix in DW11_MIXES)))
for name in phases
    println(rpad(name, 16), join((@sprintf("%10.2f", 1000 * dw11k_amount(states[mix][end], name)) for mix in DW11_MIXES)))
end
xs = collect(eachindex(phases))
w = 0.2
fig = plot(; xticks = (xs, collect(phases)), xrotation = 30, ylabel = "mmol per 100 g of binder", legend = :topright,
           size = (900, 400), left_margin = 6Plots.mm, bottom_margin = 12Plots.mm, title = "At six months")
for (k, mix) in enumerate(DW11_MIXES)
    bar!(fig, xs .+ (k - 2.5) * w, [1000 * dw11k_amount(states[mix][end], name) for name in phases];
         bar_width = w, label = mix)
end
plot!(fig; ylims = (0, 1.1 * ylims(fig)[2]))

5. What the comparison says ​

The clinker as a whole reacts at about the measured rate, its phases do not. The table's measure, the clinker reacted, is reproduced within five points from seven days to six months in the four pastes, and seven to ten points low at one day. It hides two errors in opposite directions. The law dissolves the alite too slowly at first, 25 wt.% of the solids of the plain cement at one day where 15 are left, and then lets it stall, at 6.7 wt.% at six months where the measurement finds 1.4; and it dissolves the belite from the first day, 8.9 against 17.1 wt.% at seven days, where the pastes leave it barely touched for a month. The parameters are not this clinker's: Section 6 fits those of the alite on the plain paste and tests them on the three others.

Without fly ash the portlandite is the measured one. In the plain and in the limestone cement it is within two points of the measurement at every age, the measurement being good to ±1 wt.%. The ettringite of the limestone cement is within three points, and the limestone holds it as De Weerdt et al. (2011) found, as monocarbonate takes the aluminum; in the plain cement it falls below the measurement after a month, the minimization turning part of it into monosulfate, which the authors also found, but more of it.

With fly ash the portlandite and, without limestone, the ettringite are lost. The glass, at the degree of reaction De Weerdt et al. (2011) measured, consumes the portlandite at equilibrium: at six months a fifth of the measured amount is left in the paste without limestone, under half in the paste with it. This is the finding of the validation page at measured extents, which the kinetics carries in time: the C-S-H of this phase list, CSHQ, takes no aluminum and stays at the calcium-to-silicon ratio of a gel in equilibrium with portlandite, where the authors measured a gel poorer in calcium holding aluminum. Without limestone, the aluminum of the glass then goes to the AFm phases and to hydrogarnet, and the ettringite is gone from 28 days, where the paste keeps 7 wt.%; with limestone it goes to monocarbonate, and the ettringite stays. The two other gels the package ships do not fix it: at measured extents CASH+NK behaves as CSHQ, and CNASH_ss takes the aluminum at a calcium-to-silicon ratio a Portland cement's gel does not have (the validation page). Section 7 finds the same in time.

6. The alite calibrated on the plain cement ​

Which constants of the law the measured alite determines is first a question of the law: its rate is the least of three terms, nucleation, interaction and diffusion, and only the least acts at a given degree. The law of the alite alone is fitted on the five contents of the plain cement, its interaction and diffusion constants and the critical degree of its water/cement factor free (dw11k_alite_fit), and identifiability reads the singular values of the exact sensitivity at the fit, for a measurement good to ±1 wt.%:

julia
fit = dw11k_alite_fit(runs["OPC"])
println("constant   published     fitted")
for k in keys(fit.θ)
    @printf("%-6s %12.4g %12.4g\n", k, fit.published[k], fit.θ[k])
end
@printf("misfit over the five ages: %.2f wt.%% published, %.2f fitted\n", fit.rms_published, fit.rms)
println("singular values at the fit: ", round.(fit.identifiability.S; sigdigits = 3))
constant   published     fitted
k₂             0.05       0.6261
k₃              1.1        7.381
n₃              3.3        3.718
H             1.333        2.034
misfit over the five ages: 6.40 wt.% published, 0.43 fitted
singular values at the fit: [25.1, 1.97, 0.0, 0.0]

The four pastes again, the alite under the fitted constants, the rest as before: the plain cement is the paste the constants were fitted on, the three others test them.

julia
calibrated = Dict{String, Any}(mix => dw11k_run(setup, mix; alite = fit.θ) for mix in DW11_MIXES)
recalc = Dict(mix => dw11k_contents(calibrated[mix], dw11k_replay(calibrated[mix], days)) for mix in DW11_MIXES)
measured(mix, d, q) = something(dw11_phase_content(mix, d, q), NaN)
for mix in DW11_MIXES
    println(mix, ", wt.% published/calibrated/measured")
    println("  days         C3S                 OPC reacted            portlandite")
    for (k, d) in enumerate(days)
        @printf("%6d   %5.1f/%5.1f/%5.1f    %5.1f/%5.1f/%5.1f    %5.1f/%5.1f/%5.1f\n", d,
                contents[mix][k]["C3S"], recalc[mix][k]["C3S"], measured(mix, d, "C3S"),
                contents[mix][k]["opc_reacted"], recalc[mix][k]["opc_reacted"], measured(mix, d, "opc_reacted"),
                contents[mix][k]["portlandite"], recalc[mix][k]["portlandite"], measured(mix, d, "portlandite"))
    end
end
OPC, wt.% published/calibrated/measured
  days         C3S                 OPC reacted            portlandite
     1    25.3/ 14.8/ 15.3     44.2/ 56.9/ 51.7     11.1/ 14.9/ 12.6
     7    11.8/  6.4/  6.5     70.9/ 77.3/ 68.0     17.7/ 19.8/ 18.9
    28     9.0/  3.7/  4.5     78.8/ 84.9/ 74.3     19.1/ 21.0/ 19.0
    90     7.4/  2.4/  2.0     83.1/ 88.9/ 84.7     19.8/ 21.7/ 21.8
   180     6.7/  1.8/  1.4     84.9/ 90.5/ 87.1     20.1/ 21.9/ 21.9
OPC-L, wt.% published/calibrated/measured
  days         C3S                 OPC reacted            portlandite
     1    24.2/ 14.2/ 13.0     43.8/ 56.6/ 54.0     10.5/ 14.3/ 11.5
     7    10.7/  6.1/  6.1     71.6/ 77.4/ 69.6     17.1/ 18.9/ 18.0
    28     7.7/  3.5/  2.9     80.0/ 85.2/ 77.3     18.4/ 20.0/ 18.3
    90     6.2/  2.3/  2.2     84.4/ 89.2/ 84.5     19.1/ 20.6/ 18.8
   180     5.5/  1.7/  1.6     86.4/ 91.0/ 87.6     19.4/ 20.9/ 21.0
OPC-FA, wt.% published/calibrated/measured
  days         C3S                 OPC reacted            portlandite
     1    17.2/ 10.2/  9.2     41.7/ 54.5/ 49.1      6.8/  9.6/  8.7
     7     7.6/  4.4/  2.4     70.0/ 75.8/ 69.8      9.2/ 10.5/ 14.0
    28     4.1/  2.6/  NaN     81.9/ 84.6/ 79.0      7.3/  8.0/ 13.7
    90     2.4/  1.7/  NaN     88.1/ 89.5/ 84.0      4.3/  4.6/ 12.5
   180     1.8/  1.3/  NaN     90.7/ 91.6/ 87.6      2.5/  2.7/ 11.3
OPC-FA-L, wt.% published/calibrated/measured
  days         C3S                 OPC reacted            portlandite
     1    17.2/ 10.2/  8.8     41.7/ 54.5/ 50.8      6.9/  9.7/  8.8
     7     7.6/  4.4/  1.8     70.3/ 76.0/ 71.6      9.6/ 10.9/ 13.5
    28     4.1/  2.6/  0.6     82.2/ 84.9/ 82.8      8.3/  8.9/ 12.8
    90     2.4/  1.6/  NaN     88.3/ 89.7/ 87.4      6.2/  6.5/ 12.2
   180     1.8/  1.2/  NaN     90.9/ 91.8/ 89.5      4.7/  5.0/ 10.8
julia
alite = map(enumerate(DW11_MIXES)) do (k, mix)
    p = plot(; xscale = :log10, xlabel = "age (days)", ylabel = "C3S, wt.% of the solids",
             title = mix == "OPC" ? "OPC, the paste fitted on" : mix,
             titlefontsize = 10, legend = k == 1 ? :topright : false)
    plot!(p, days, [contents[mix][j]["C3S"] for j in eachindex(days)]; lw = 2, ls = :dash, color = :grey50, label = "published")
    plot!(p, days, [recalc[mix][j]["C3S"] for j in eachindex(days)]; lw = 2, color = :steelblue, label = "calibrated")
    scatter!(p, days, [measured(mix, d, "C3S") for d in days]; color = :black, marker = :diamond, label = "measured")
end
plot(alite...; layout = (1, 4), size = (1100, 330), left_margin = 6Plots.mm, bottom_margin = 7Plots.mm)

The fit determines two combinations of the four constants, those of the diffusion term. The interaction constant and the critical degree come out where they no longer act, the two zero singular values: the data say only that they are larger than the published ones, which cap the alite of this clinker where it does not slow down. With a diffusion constant seven times the published one, the alite of the plain cement is the measured one within half a point at every age.

The limestone cement, which nothing was fitted on, follows: its alite is within 1.2 points of the measurement at every age. With fly ash the measured alite is faster still, 2.4 and 1.8 wt.% at seven days against 4.4 computed: the filler effect of the fly ash, which De Weerdt et al. (2011) find, and which a law written for each phase of the cement alone does not carry.

The clinker reacted is now overestimated, by 3 to 11 points, because the belite still reacts as the published law makes it, too fast for this clinker, and nothing compensates it any more. Under this law the rate of the belite is always its diffusion term, greatest at the mixing and decreasing from there, where the belite of these pastes waits a month: no value of the constants holds it. The portlandite of the pastes without fly ash follows the alite, within two points from seven days and two to three too high at one day.

7. The two other gels, in time ​

The two fly-ash pastes again, with CNASH_ss and then CASH+NK in place of CSHQ, the rest of the phase list and the laws unchanged, the alite under its published constants as in Sections 2 to 5; CASH+NK without the aqueous ion pairs its authors left out when fitting it (Miron et al., 2022; Section 3.2), as on the validation page. The members of CASH+NK are mixed under the compound energy formalism, whose activities depend on the standard Gibbs energies of the members, which the run evaluates at its temperature.

julia
gels = ("CSHQ", "CNASH_ss", "CASH+NK")
fa_mixes = ("OPC-FA", "OPC-FA-L")
gel_days = [1, 7, 28, 90, 140, 180]
gel_states = Dict{Tuple{String, String}, Any}()
gel_contents = Dict{Tuple{String, String}, Any}()
for gel in gels, mix in fa_mixes
    r = gel == "CSHQ" ? runs[mix] : dw11k_run(dw11k_setup(; gel), mix)
    gel_states[(gel, mix)] = dw11k_replay(r, gel_days)
    gel_contents[(gel, mix)] = dw11k_contents(r, gel_states[(gel, mix)][[1, 2, 3, 4, 6]])
end
for mix in fa_mixes
    println(mix, ", wt.%            portlandite                       ettringite")
    println("  days      CSHQ  CNASH_ss  CASH+NK  measured      CSHQ  CNASH_ss  CASH+NK  measured")
    for (k, d) in enumerate(days)
        @printf("%6d  %8.1f %8.1f %8.1f %8.1f   %8.1f %8.1f %8.1f %8.1f\n", d,
                (gel_contents[(g, mix)][k]["portlandite"] for g in gels)..., measured(mix, d, "portlandite"),
                (gel_contents[(g, mix)][k]["ettringite"] for g in gels)..., measured(mix, d, "ettringite"))
    end
end
OPC-FA, wt.%            portlandite                       ettringite
  days      CSHQ  CNASH_ss  CASH+NK  measured      CSHQ  CNASH_ss  CASH+NK  measured
     1       6.8      9.3      7.1      8.7        8.5      8.8      8.3      9.0
     7       9.2     15.7      9.7     14.0        4.5      8.6      4.6      7.4
    28       7.3     15.8      8.0     13.7        0.0      5.4      0.0      7.5
    90       4.3     14.7      4.9     12.5        0.0      3.0      0.0      6.6
   180       2.5     13.8      3.1     11.3        0.0      1.8      0.0      6.6
OPC-FA-L, wt.%            portlandite                       ettringite
  days      CSHQ  CNASH_ss  CASH+NK  measured      CSHQ  CNASH_ss  CASH+NK  measured
     1       6.9      9.4      7.2      8.8        8.5      8.8      8.3      9.3
     7       9.6     15.9     10.2     13.5        8.7      8.9      8.9      9.2
    28       8.3     16.3      9.0     12.8        8.5      8.7      8.8      9.5
    90       6.2     15.5      6.9     12.2        8.3      8.6      8.7     10.5
   180       4.7     14.7      5.5     10.8        8.3      8.5      8.6     10.9
julia
gel_panels = map(fa_mixes) do mix
    p = plot(; xscale = :log10, xlabel = "age (days)", ylabel = "portlandite, wt.% of the solids", title = mix,
             titlefontsize = 10, legend = mix == first(fa_mixes) ? :bottomleft : false)
    for g in gels
        plot!(p, days, [gel_contents[(g, mix)][k]["portlandite"] for k in eachindex(days)]; lw = 2, marker = :circle,
              ms = 3, label = g)
    end
    scatter!(p, days, [measured(mix, d, "portlandite") for d in days]; color = :black, marker = :diamond, label = "measured")
end
plot(gel_panels...; layout = (1, 2), size = (900, 380), left_margin = 6Plots.mm, bottom_margin = 6Plots.mm)

The C-S-H of each, against the SEM-EDX analyses of De Weerdt et al. (2011), at one day and at 140 days:

julia
println("                     Ca/Si, 1 d and 140 d     Al/Si, 1 d and 140 d")
@printf("measured             %8.2f %8.2f      %8.2f %8.2f\n",
        dw11_value("csh_ca_si_fly_ash_1d"), dw11_value("csh_ca_si_fly_ash_140d"),
        dw11_value("csh_al_si_fly_ash_1d"), dw11_value("csh_al_si_fly_ash_140d"))
for mix in fa_mixes, gel in gels
    early, late = dw11k_gel(gel_states[(gel, mix)][1], gel), dw11k_gel(gel_states[(gel, mix)][5], gel)
    @printf("%-9s %-9s  %8.2f %8.2f      %8.3f %8.3f\n", mix, gel, early.Ca_Si, late.Ca_Si, early.Al_Si, late.Al_Si)
end
                     Ca/Si, 1 d and 140 d     Al/Si, 1 d and 140 d
measured                 1.70     1.40          0.06     0.13
OPC-FA    CSHQ           1.58     1.58         0.000    0.000
OPC-FA    CNASH_ss       1.12     1.16         0.090    0.107
OPC-FA    CASH+NK        1.57     1.55         0.000    0.000
OPC-FA-L  CSHQ           1.58     1.58         0.000    0.000
OPC-FA-L  CNASH_ss       1.12     1.16         0.090    0.101
OPC-FA-L  CASH+NK        1.57     1.55         0.000    0.000

In time as at the measured extents, neither gel reproduces the pastes. The gel of CASH+NK is that of CSHQ, a Ca/Si between 1.55 and 1.58 at one day and at 140 days, with no aluminum, and the portlandite with it, within a point. CNASH_ss takes aluminum, an Al/Si rising from 0.09 to 0.10 or 0.11 where De Weerdt et al. (2011) measure 0.06 rising to 0.13, but at a Ca/Si of 1.12 to 1.16 from the first day, where the paper measures 1.7 falling to 1.4. The calcium its gel does not take stays in portlandite, above the measurement by 1.7 to 3.9 points from seven days, and without limestone the ettringite goes more slowly, 1.8 wt.% left at six months against none with CSHQ and 6.6 measured. What the measurement asks of the model is a gel whose Ca/Si falls with time as it takes aluminum, beside portlandite: none of the three does both, and CSHQ stays the gel of these pages.

Where to go next ​

Validation against measured blended pastes separates the thermodynamics from the kinetics on the same pastes, and Kinetics under partial equilibrium writes the formulation these runs integrate.