Skip to content

Hemicarbonate and monocarbonate: the carbonate of the AFm phases ​

Before this page

Carbonation of a CEM I 52.5 N and of its blends, for the carbonation of a whole paste, of which this is the part that happens in the AFm.

A paste that takes up carbonate turns its AFm phases from hydroxide to hemicarbonate, then to monocarbonate, before calcite forms. Georget et al. (2022) hydrated 10 g of C₃A with portlandite and calcite in the proportions of these phases, 28 days at 20 °C, replacing portlandite by calcite from one sample to the next, with ζ the molar fraction of calcium carbonate among the two; they published with their data set (Georget et al., 2021) the same series computed with GEMS (Kulik et al., 2013) and Cemdata18 (Lothenbach et al., 2019) in 101 steps. This page computes those steps, the water of the GEMS run, not given with the data set, taken at 2.7 times the solids of the experiments.

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

rows = ge22_series()
t = ge22_steps()
g(f, k) = ustrip(us"g", getproperty(t, f)[k])
println("certified: ", count(r -> r.certified, rows), " of ", length(rows))
println("    ζ    katoite    hemicarbonate   monocarbonate      calcite     portlandite   (g, here / GEMS)")
for k in 1:10:101
    r = rows[k]
    @printf("%5.3f  %5.2f/%5.2f   %6.2f/%6.2f   %6.2f/%6.2f   %5.2f/%5.2f   %5.2f/%5.2f\n", r.zeta,
            r.katoite, g(:katoite, k), r.hemicarbonate, g(:hemicarbonate, k), r.monocarbonate, g(:monocarbonate, k),
            r.calcite, g(:calcite, k), r.portlandite, g(:portlandite, k))
end
gap = maximum(maximum(abs(getproperty(rows[k], f) - g(f, k)) for f in (:katoite, :hemicarbonate, :monocarbonate, :calcite, :portlandite)) for k in eachindex(rows))
@printf("largest difference over the 101 steps: %.3f g\n", gap)
certified: 101 of 101
    ζ    katoite    hemicarbonate   monocarbonate      calcite     portlandite   (g, here / GEMS)
1.000   0.00/ 0.00     0.00/  0.00    20.41/ 20.39    0.71/ 0.71    0.85/ 0.86
0.911   0.00/ 0.00     0.00/  0.00    20.41/ 20.39    0.28/ 0.28    1.13/ 1.14
0.820   0.00/ 0.00     1.73/  1.70    18.67/ 18.68    0.00/ 0.00    1.29/ 1.31
0.726   0.00/ 0.00     6.58/  6.55    13.78/ 13.79    0.00/ 0.00    1.26/ 1.28
0.630   0.00/ 0.00    11.43/ 11.40     8.90/  8.91    0.00/ 0.00    1.22/ 1.24
0.532   0.00/ 0.00    16.28/ 16.25     4.01/  4.03    0.00/ 0.00    1.18/ 1.20
0.431   0.58/ 0.57    19.40/ 19.40     0.00/  0.00    0.00/ 0.00    1.26/ 1.27
0.328   3.83/ 3.82    14.55/ 14.55     0.00/  0.00    0.00/ 0.00    1.85/ 1.87
0.221   7.08/ 7.07     9.70/  9.70     0.00/  0.00    0.00/ 0.00    2.45/ 2.47
0.112  10.33/10.32     4.85/  4.85     0.00/  0.00    0.00/ 0.00    3.05/ 3.06
0.000  13.58/13.57     0.00/  0.00     0.00/  0.00    0.00/ 0.00    3.65/ 3.66
largest difference over the 101 steps: 0.030 g
julia
z = [r.zeta for r in rows]
fig = plot(; xlabel = "ζ, CaCO₃ / (CaCO₃ + Ca(OH)₂), molar", ylabel = "g", legend = :outerright,
           size = (860, 420), left_margin = 5Plots.mm, bottom_margin = 5Plots.mm,
           title = "9.7 g of C₃A, water 2.7 × the solids, 20 °C; dashed: GEMS", titlefontsize = 11)
for (k, (f, lab)) in enumerate(((:katoite, "katoite"), (:hemicarbonate, "hemicarbonate"),
                                (:monocarbonate, "monocarbonate"), (:calcite, "calcite"), (:portlandite, "portlandite")))
    plot!(fig, z, [getproperty(r, f) for r in rows]; lw = 2, color = k, label = lab)
    plot!(fig, ustrip.(t.zeta_CO3), [g(f, j) for j in eachindex(t.zeta_CO3)]; lw = 2, ls = :dash, color = k, label = "")
end
fig

The two calculations agree to 0.03 g of a solid of 20 g at every step. Below ζ = 0.452 the carbonate is all in hemicarbonate, beside katoite; up to 0.857 hemicarbonate turns into monocarbonate; above, calcite remains:

julia
b = ge22_breakpoints(rows)
@printf("katoite gone at ζ = %.4f, hemicarbonate gone at ζ = %.4f\n", b.katoite_gone, b.hemicarbonate_gone)
meas = literature_table("Georget2022", "carbonate_series")
println("  ζ     measured (Table 7)      here")
for i in eachindex(meas.pH)
    z = ustrip(meas.zeta_CO3_nominal[i])
    @printf("%4.2f   %-22s %s\n", z, meas.identified_phases[i], join(ge22_phases(rows, z), ", "))
end
@printf("pH %.2f here, %.2f to %.2f by GEMS, %.2f to %.2f measured\n", rows[1].pH, minimum(ustrip.(t.pH)),
        maximum(ustrip.(t.pH)), minimum(ustrip.(meas.pH)), maximum(ustrip.(meas.pH)))
katoite gone at ζ = 0.4515, hemicarbonate gone at ζ = 0.8565
  ζ     measured (Table 7)      here
┌ Warning: Assignment to `z` in soft scope is ambiguous because a global variable by the same name exists: `z` will be treated as a new local. Disambiguate by using `local z` to suppress this warning or `global z` to assign to the existing global variable.
└ @ hemicarbonate.md:59
0.25   Hc, katoite, CH        Hc, katoite, CH
0.50   Hc, Mc, CH             Hc, Mc, CH
0.50   Hc, Mc, CH             Hc, Mc, CH
0.75   Mc, Hc, CH, CC         Hc, Mc, CH
1.00   Mc, CH, CC             Mc, CH, CC
pH 12.66 here, 12.70 to 12.74 by GEMS, 12.71 to 12.76 measured

The phases are those the samples held, but for the calcite found beside monocarbonate and hemicarbonate at ζ = 0.75, which the equilibrium has not yet formed there. The pH is 0.05 to 0.1 below both: the sodium the calcium carbonate brought, which was not measured, is not in this calculation.