Page MenuHomec4science

cement_hydration.py
No OneTemporary

File Metadata

Created
Fri, May 17, 03:02

cement_hydration.py

#Copyright (c) 2014,2015 Fabien Georget <fabieng@princeton.edu>, Princeton
#University #All rights reserved.
#
#Redistribution and use in source and binary forms, with or without
#modification, are permitted provided that the following conditions are met:
#
#1. Redistributions of source code must retain the above copyright notice, this
#list of conditions and the following disclaimer.
#
#2. Redistributions in binary form must reproduce the above copyright notice,
#this list of conditions and the following disclaimer in the documentation
#and/or other materials provided with the distribution.
#
#3. Neither the name of the copyright holder nor the names of its contributors
#may be used to endorse or promote products derived from this software without
#specific prior written permission.
#
#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
#ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
#DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
#FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
#DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
#SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
#OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
#OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import specmicp.database as database
import specmicp.constraints as formulation
import specmicp.solver
MASS_PERCENT_INDEX = 0
HYDRATION_INDEX = 1
def hydration(
minerals,
wc,
database_path="",
database_manager=None,
aqueous_species=None,
percent_v_entrained_air=0.0,
list_minerals_to_keep=None,
list_extra_component=[],
length_unit="meter",
previous_sol=None,
saturated_system=False
):
"""Thermodynamic Cement hydration
Return a SpecMiCPSolution
The first argument is a dictionary :
{label: (mass_percent, hydration degree)}
A new database is created for each p
Example :
>>> sol = hydration(
{"C3S": (0.8, 1.0), "C3A": (0.1, 1.0), "C4AF": (0.1, 1.0)},
0.4,
"../data/cemdata.js",
percent_v_entrained_air=0.0)
"""
if database_manager is None:
db = database.DatabaseManager(database_path)
swapping = {
"H[+]": "HO[-]",
"Al[3+]": "Al(OH)4[-]",
"Fe[2+]": "Fe(OH)4[-]",
"Si(OH)4": "SiO(OH)3[-]"
}
db.swap_components(swapping)
db.remove_gas_phases()
else:
db = database_manager
if length_unit == "meter":
scaling = 1.0
elif length_unit == "decimeter":
scaling = 1e3
elif length_unit == "centimer":
scaling = 1e6
else:
raise ValueError("Unknown length unit")
scaling_M = 1.0
rho_minerals = []
is_kinetic = []
# find the cement mass
# --------------------
sum_for_cement_mass = 0.0
for (label, value) in minerals.items():
try:
idm = db.mineral_label_to_id(label)
rho_minerals.append(scaling_M/scaling*db.density_mineral(idm))
is_kinetic.append(False)
except ValueError:
idm = db.mineral_kinetic_label_to_id(label)
rho_minerals.append(scaling_M/scaling*db.density_mineral_kinetic(idm))
is_kinetic.append(True)
sum_for_cement_mass += value[MASS_PERCENT_INDEX] / rho_minerals[-1]
sum_for_cement_mass += wc / (997.0 / scaling)
mc = (1.0 - percent_v_entrained_air) / sum_for_cement_mass
inert_volume = 0.0
# set the formulation
# -------------------
system = formulation.SpecMiCPFormulation(db)
for (index, (label, value)) in enumerate(minerals.items()):
reactant_mass = value[MASS_PERCENT_INDEX] * mc
concentration = value[HYDRATION_INDEX] * reactant_mass
inert = (1.0 - value[HYDRATION_INDEX]) * reactant_mass
if is_kinetic[index]:
concentration /= scaling_M*db.molar_mass_mineral_kinetic(idm)
inert /= rho_minerals[index]
else:
concentration /= scaling_M*db.molar_mass_mineral(idm)
inert /= rho_minerals[index]
system.add_mineral(label, concentration)
inert_volume += inert
system.set_inert_volume_fraction(inert_volume)
system.set_mass_solution(wc * mc)
if aqueous_species is not None:
for (label, value) in aqueous_species.items():
system.add_aqueous_species(label, value)
if list_minerals_to_keep is not None:
system.set_list_minerals(list_minerals_to_keep)
system.initialize_system()
if saturated_system:
system.set_saturated_system()
system.set_charge_keeper("HO[-]")
# solve the problem
# -----------------
the_solver = specmicp.solver.SpecMiCPSolver(db, system, previous_sol)
the_solver.set_length_unit(length_unit)
the_solver.set_maximum_step_length(20, 100)
the_solver.enable_non_monotone_linesearch()
the_solver.disable_condition_check()
the_solver.set_tolerances(1e-8, 1e-12)
the_solver.set_non_ideality_tolerance(1e-12)
if previous_sol is None:
map_init = {"HO[-]": -2.0, "Ca[2+]": -2.0, "SiO(OH)3[-]": -5.0}
extra_components = {"Al(OH)4[-]": -3.0, "SO4[2-]": -3.0, "Fe(OH)4[-]": -4.0}
for (label, value) in extra_components.items():
try:
_ = db.component_label_to_id(label)
map_init[label] = value
except ValueError:
pass
the_solver.initialize_variables(0.5, map_init)
the_solver.solve()
# return the solution
# -------------------
return the_solver.get_solution()
def hydration_oxyde(
oxyde_formulation,
density_cement,
wc,
loss_of_ignition,
database_path="",
database_manager=None,
aqueous_species=None,
percent_v_entrained_air=0.0,
list_minerals_to_keep=None,
list_extra_component=[],
length_unit="meter",
previous_sol=None,
saturated_system=False,
degree_hydration=1.0
):
"""Thermodynamic Cement hydration
No hydration degree
Return a SpecMiCPSolution
The first argument is a dictionary :
{label: (mass_percent, hydration degree)}
A new database is created for each p
"""
if database_manager is None:
db = database.DatabaseManager(database_path)
swapping = {
"H[+]": "HO[-]",
"Al[3+]": "Al(OH)4[-]",
"Fe[2+]": "Fe(OH)4[-]",
"Si(OH)4": "SiO(OH)3[-]"
}
db.swap_components(swapping)
db.remove_gas_phases()
else:
db = database_manager
if length_unit == "meter":
scaling = 1.0
elif length_unit == "decimeter":
scaling = 1e3
elif length_unit == "centimer":
scaling = 1e6
else:
raise ValueError("Unknown length unit")
scaling_M = 1.0
# find the cement mass
# --------------------
sum_for_cement_mass = 1.0/density_cement + wc / (997.0 / scaling)
mc = (1.0 - percent_v_entrained_air) / sum_for_cement_mass
# set the formulation
# -------------------
system = formulation.SpecMiCPFormulation(db)
for (index, (label, value)) in enumerate(oxyde_formulation.items()):
concentration = value * mc * degree_hydration
concentration /= scaling_M*db.l_molar_mass_mineral_kinetic(label)
system.add_mineral(label, concentration)
system.set_inert_volume_fraction(mc*(1.0-degree_hydration)/density_cement)
system.set_mass_solution(wc * mc + loss_of_ignition * mc)
if aqueous_species is not None:
for (label, value) in aqueous_species.items():
system.add_aqueous_species(label, value)
if list_minerals_to_keep is not None:
system.set_list_minerals(list_minerals_to_keep)
system.initialize_system()
if saturated_system:
system.set_saturated_system()
system.set_charge_keeper("HO[-]")
# solve the problem
# -----------------
the_solver = specmicp.solver.SpecMiCPSolver(db, system, previous_sol)
the_solver.set_length_unit(length_unit)
the_solver.set_maximum_step_length(20, 100)
the_solver.enable_non_monotone_linesearch()
the_solver.disable_condition_check()
the_solver.set_tolerances(1e-8, 1e-12)
the_solver.set_non_ideality_tolerance(1e-12)
if previous_sol is None:
map_init = {"HO[-]": -2.0, "Ca[2+]": -2.0, "SiO(OH)3[-]": -5.0}
extra_components = {"Al(OH)4[-]": -3.0, "SO4[2-]": -3.0, "Fe(OH)4[-]": -4.0}
for (label, value) in extra_components.items():
try:
_ = db.component_label_to_id(label)
map_init[label] = value
except ValueError:
pass
the_solver.initialize_variables(0.5, map_init)
the_solver.solve()
# return the solution
# -------------------
return the_solver.get_solution()

Event Timeline