Skip to content

Chloride and the AFm phases: a model Portland system titrated by CaCl₂ ​

Before this page

Friedel's and Kuzel's salts from 0 to 99 °C, the same mixture heated, on which this page builds.

Chloride entering a paste is bound by its AFm phases: the sulfate AFm becomes Kuzel's salt, which becomes Friedel's salt as chloride grows; with carbonate, the monocarbonate becomes Friedel's salt directly. Balonis et al. (2010) equilibrated at 25 °C the model mixture of a Portland paste, 0.01 mol of C₃A, 0.015 mol of portlandite and 0.01 mol of calcium sulfate in 60 mL of water, without and with 0.0075 mol of calcite, with CaCl₂ up to 2Cl/Al₂O₃ = 1, and identified the phases by XRD. This page computes the titration with Cemdata18 (Lothenbach et al., 2019), on the system of the companion page on temperature.

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

ratios = 0.0:0.02:1.1
free = ba10_titration(ratios)
carb = ba10_titration(ratios; calcite = true)
println("certified: ", count(r -> r.certified, free) + count(r -> r.certified, carb), " of ", 2 * length(ratios))
b = ba10_boundaries(free)
@printf("without calcite: sulfate AFm gone at %.2f, Kuzel's salt from %.2f to %.2f (2Cl/Al2O3)\n",
        b.monosulfate_gone, b.kuzel_first, b.kuzel_gone)
xrd = literature_table("Balonis2010", "xrd_phases")
row(rows, r) = rows[argmin([abs(x.ratio - r) for x in rows])]
println("system              2Cl/Al2O3   XRD              here")
for i in eachindex(xrd.phases)
    rows = xrd.system[i] == "carbonate-free" ? free : carb
    r = ustrip(xrd.cl2_al2o3_nominal[i])
    @printf("%-19s %8.1f   %-16s %s\n", xrd.system[i], r, xrd.phases[i], ba10_phases(row(rows, r)))
end
certified: 112 of 112
without calcite: sulfate AFm gone at 0.44, Kuzel's salt from 0.04 to 0.78 (2Cl/Al2O3)
system              2Cl/Al2O3   XRD              here
carbonate-free           0.0   E, Ms, P         E, Ms, P
carbonate-free           0.3   E, Ms, Ks, P     E, Ms, Ks, P
carbonate-free           0.5   E, Ks, P, Cc     E, Ks, P
carbonate-free           1.0   E, Fs, P         E, Fs, P
carbonate-bearing        0.0   E, Mc, P         E, Mc, P, Cc
carbonate-bearing        1.0   E, Fs, P, Cc     E, Fs, P, Cc
julia
phases = ((:ettringite, "ettringite"), (:monosulfate, "sulfate AFm"), (:kuzel, "Kuzel's salt"),
          (:friedel, "Friedel's salt"), (:monocarbonate, "monocarbonate"))
panel(rows, title; legend = false) = (p = plot(; xlabel = "2Cl/Al₂O₃ added as CaCl₂", ylabel = "mol per mol of Al₂O₃",
                               title, titlefontsize = 10, legend, ylims = (0, 1.05));
                      for (k, (f, lab)) in enumerate(phases)
                          plot!(p, [r.ratio for r in rows], [getproperty(r, f) for r in rows]; lw = 2, color = k, label = lab)
                      end; p)
plot(panel(free, "0.01 mol C₃A, SO₃/Al₂O₃ = 1"; legend = :topright), panel(carb, "the same with 0.0075 mol of calcite");
     layout = (1, 2), size = (900, 380), left_margin = 5Plots.mm, bottom_margin = 6Plots.mm)

E is ettringite, Ms the sulfate AFm, Ks and Fs Kuzel's and Friedel's salts, Mc monocarbonate, P portlandite and Cc calcite. Without calcite, the sulfate AFm is gone at 0.44 here and between 0.41 and 0.45 in the calculation of Balonis et al. (2010), Kuzel's salt at 0.78 here and between 0.68 and 0.72 there, on a grid of 0.02; the phases of every sample are found, but for traces of calcite, which the carbonate-free mixture held from the air, and the calcite of the carbonate-bearing mixture before any chloride, which the equilibrium keeps and the XRD did not report.

julia
meas = literature_table("Balonis2010", "fig8b_measured_solution")
println("2Cl/Al2O3    Ca (mmol/L)     Cl (mmol/L)        pH     (here / measured)")
for i in eachindex(meas.pH)
    r = ustrip(meas.cl2_al2o3[i]); x = row(free, r)
    @printf("%8.2f   %5.1f / %5.1f   %6.1f / %5.1f   %5.2f / %5.2f\n", r, x.Ca, ustrip(meas.Ca[i]),
            x.Cl, ustrip(meas.Cl[i]), x.pH, ustrip(meas.pH[i]))
end
@printf("solid volume, 2Cl/Al2O3 0 to 1: %+.0f %% without calcite, %+.0f %% with\n",
        100 * (row(free, 1.0).solids / row(free, 0.0).solids - 1), 100 * (row(carb, 1.0).solids / row(carb, 0.0).solids - 1))
2Cl/Al2O3    Ca (mmol/L)     Cl (mmol/L)        pH     (here / measured)
    0.00    20.3 /  19.7      0.0 /   0.0   12.48 / 12.50
    0.29    24.6 /  25.0     10.3 /  10.4   12.44 / 12.44
    0.50    35.6 /  40.2     34.9 /  18.3   12.39 / 12.38
    1.00    74.6 /  66.6    116.8 / 143.0   12.28 / 12.24
solid volume, 2Cl/Al2O3 0 to 1: +26 % without calcite, +6 % with
julia
r_meas = ustrip.(meas.cl2_al2o3)
fig = plot(; xlabel = "2Cl/Al₂O₃ added as CaCl₂", ylabel = "mmol/L", legend = :topleft, size = (750, 400),
           left_margin = 5Plots.mm, bottom_margin = 5Plots.mm, title = "Pore solution, without calcite, 25 °C")
plot!(fig, [r.ratio for r in free], [r.Cl for r in free]; lw = 2, color = 1, label = "Cl, here")
scatter!(fig, r_meas, ustrip.(meas.Cl); color = 1, label = "Cl, measured")
plot!(fig, [r.ratio for r in free], [r.Ca for r in free]; lw = 2, color = 2, label = "Ca, here")
scatter!(fig, r_meas, ustrip.(meas.Ca); color = 2, marker = :diamond, label = "Ca, measured")
fig

The solution of the samples, read on the figure of Balonis et al. (2010), is reproduced while the sulfate AFm remains; once Kuzel's salt alone holds the chloride the calculation leaves twice the measured chloride in solution, and at 2Cl/Al₂O₃ = 1 a fifth less. Binding chloride swells the solids, by about a quarter without calcite and by a twentieth with it, against 29 % and 7 % in the calculation of the article.