diff --git a/cython/specmicp/cement_hydration.py b/cython/specmicp/cement_hydration.py index d36b80d..c73a333 100644 --- a/cython/specmicp/cement_hydration.py +++ b/cython/specmicp/cement_hydration.py @@ -1,281 +1,281 @@ #Copyright (c) 2014,2015 Fabien Georget , 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*degree_hydration/density_cement) + 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()