diff --git a/COPYING b/COPYING index b491721..ee0d1b5 100644 --- a/COPYING +++ b/COPYING @@ -1,24 +1,27 @@ -Copyright (c) 2014, Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. diff --git a/cython/specmicp/__init__.py b/cython/specmicp/__init__.py index 24033b4..1cb6f47 100644 --- a/cython/specmicp/__init__.py +++ b/cython/specmicp/__init__.py @@ -1,25 +1,28 @@ -# 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: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of the Princeton University 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 OWNER 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. +#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. diff --git a/cython/specmicp/cement_hydration.py b/cython/specmicp/cement_hydration.py index f1d49d9..d36b80d 100644 --- a/cython/specmicp/cement_hydration.py +++ b/cython/specmicp/cement_hydration.py @@ -1,278 +1,281 @@ -# -*- coding: utf-8 -*- -# 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: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of SpecMiCP 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 OWNER 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. +#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_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() \ No newline at end of file + return the_solver.get_solution() diff --git a/cython/specmicp/constraints.pxd b/cython/specmicp/constraints.pxd index 5514558..421301f 100644 --- a/cython/specmicp/constraints.pxd +++ b/cython/specmicp/constraints.pxd @@ -1,85 +1,89 @@ -# Copyright (c) 2014,2015 Fabien Georget , Princeton University -# All rights reserved. +#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. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of the Princeton University 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 OWNER 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. from eigen cimport VectorXd from libcpp.map cimport map as cmap from libcpp.string cimport string from libcpp.vector cimport vector from memory cimport shared_ptr from database cimport DatabaseManager, DataContainer # The constraints # --------------- cdef extern from "specmicp/adimensional/adimensional_system_structs.hpp" namespace "specmicp": cdef cppclass AdimensionalSystemConstraints: AdimensionalSystemConstraints() AdimensionalSystemConstraints(const AdimensionalSystemConstraints& other) void set_total_concentrations(const VectorXd&) void enable_conservation_water() void disable_conservation_water() void set_saturated_system() void disable_surface_model() void enable_surface_model(double) void set_charge_keeper(int) void add_fixed_fugacity_gas(int, int, float) void add_fixed_activity_component(int, double) void set_inert_volume_fraction(double) # The formulation of the problem # ------------------------------ cdef extern from "specmicp/problem_solver/formulation.hpp" namespace "specmicp": cdef cppclass Formulation: Formulation() void set_mass_solution(double) void add_aqueous_species(const string&, double) void add_mineral(const string&, double) void keep_component(const string&) void set_minerals_list(const vector[string]& list) # Dissolve the formulation # ------------------------ cdef extern from "specmicp/problem_solver/dissolver.hpp" namespace "specmicp": cdef cppclass Dissolver: Dissolver(shared_ptr[DataContainer]) VectorXd dissolve(const Formulation&) VectorXd get_total_concentration() # Wrapper for the constraints # --------------------------- cdef class SpecMiCPConstraints: cdef DatabaseManager database cdef AdimensionalSystemConstraints* constraints cdef AdimensionalSystemConstraints* _get(self) # Wrapper for the formulation # --------------------------- cdef class SpecMiCPFormulation(SpecMiCPConstraints): - cdef Formulation* formulation \ No newline at end of file + cdef Formulation* formulation diff --git a/cython/specmicp/constraints.pyx b/cython/specmicp/constraints.pyx index 2bcd1ba..4e1c244 100644 --- a/cython/specmicp/constraints.pyx +++ b/cython/specmicp/constraints.pyx @@ -1,164 +1,168 @@ -# 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: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of SpecMiCP 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 OWNER 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. +#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. + from database cimport DatabaseManager from constraints cimport SpecMiCPConstraints, AdimensionalSystemConstraints, SpecMiCPFormulation from eigen cimport VectorXd, vector_setitem from libcpp.utility cimport pair from cython.operator cimport dereference cdef class SpecMiCPConstraints: """A class managing the SpecMiCP constraints""" def __cinit__(self, DatabaseManager database not None): self.database = database self.constraints = new AdimensionalSystemConstraints() def __dealloc__(self): del self.constraints cdef AdimensionalSystemConstraints* _get(self): return self.constraints # Total concentrations # -------------------- def set_total_concentrations(self, dictionary_total_concs): """Set the total concentrations dictionary_total_concs is a dictionary mapping the labels of components to their total concentrations. """ cdef VectorXd total_concs cdef int index total_concs.setZero(self.database.nb_component) for (key, value) in dictionary_total_concs.items(): index = self.database.component_label_to_id(key) vector_setitem(total_concs, index, value) self.constraints.set_total_concentrations(total_concs) # Water conservation # ------------------ def enable_conservation_water(self): """Enable the conservation of water""" self.constraints.enable_conservation_water() def disable_conservation_water(self): """Disable the conservation of water. No equation is solved for the water component in this case.""" self.constraints.disable_conservation_water() def set_saturated_system(self): """The system is saturated with water""" self.constraints.set_saturated_system() # Surface model # ------------- def enable_surface_model(self, site_concentrations): """Enable the surface sorption model. The total concentration of sorption site is 'site_concentrations'""" self.constraints.enable_surface_model(site_concentrations) def disable_surface_model(self): """Disable the surface sorption model""" self.constraints.disable_surface_model() # components # ---------- def set_charge_keeper(self, label): """Set the charge keeper to be 'label' The charge keeper is in charge of the electroneutrality equation""" cdef int index index = self.database.component_label_to_id(label) self.constraints.set_charge_keeper(index) def add_fixed_fugacity_gas(self, gas_label, component_label, log_fugacity): """Set 'gas_label' to be a fixed fugacity gas""" cdef int g_index, c_index g_index = self.database.gas_label_to_id(gas_label) c_index = self.database.component_label_to_id(component_label) self.constraints.add_fixed_fugacity_gas(g_index, c_index, log_fugacity) def add_fixed_activity_component(self, component_label, log_activity): """Set 'component_label' to have a fixed fugacity""" cdef int c_index c_index = self.database.component_label_to_id(component_label) self.constraints.add_fixed_activity_component(c_index, log_activity) # Inert volume # ------------ def set_inert_volume_fraction(self, volume_fraction_inert): """Set the volume fraction of inert materials""" self.constraints.set_inert_volume_fraction(volume_fraction_inert) cdef class SpecMiCPFormulation(SpecMiCPConstraints): """The formulation of a problem""" def __cinit__(self, DatabaseManager database): self.formulation = new Formulation() def __dealloc__(self): del self.formulation def set_mass_solution(self, mass_solution): """Set the mass of the solution""" self.formulation.set_mass_solution(mass_solution) def add_aqueous_species(self, label, concentration): """Add an aqueous species to the system. An aqueous species can be in that case a component or a secondary aqueous species. 'concentration' is in moles per volume """ self.formulation.add_aqueous_species(label, concentration) def add_mineral(self, label, concentration): """Add a mineral species to the system. The mineral can be governed by equilibrium or by kinetics. 'concentration' is in moles per volume """ self.formulation.add_mineral(label, concentration) def keep_component(self, label): """Keep the component 'label' in the database even if it does not exist in the initial system. This must be used if the component will be used later in the computation """ self.formulation.keep_component(label) def set_list_minerals(self, list_minerals): """Set the list of minerals at equilibrium If this function is not called, or the size of the list is zero, all minerals in the database will be used. """ cdef vector[string] list = list_minerals self.formulation.set_minerals_list(list) def initialize_system(self): """Initialize the system by dissolving the formulation""" cdef Dissolver* dissolver = new Dissolver(self.database.get_raw_db()) cdef VectorXd total_conc = dissolver.dissolve(dereference(self.formulation)) self._get().set_total_concentrations(total_conc) - del dissolver \ No newline at end of file + del dissolver diff --git a/cython/specmicp/database.pxd b/cython/specmicp/database.pxd index 7c75039..765273d 100644 --- a/cython/specmicp/database.pxd +++ b/cython/specmicp/database.pxd @@ -1,111 +1,114 @@ -# 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: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of SpecMiCP 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 OWNER 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. +#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. from libcpp.string cimport string from libcpp.vector cimport vector from libcpp.map cimport map as cmap from libcpp cimport bool from memory cimport shared_ptr from eigen cimport MatrixXd, VectorXd # The raw container cdef extern from "database/data_container.hpp" namespace "specmicp::database": cdef cppclass DataContainer: int water_index(); int electron_index(); # basis # ----- int nb_component() int nb_aqueous_components() int get_id_component(string) string get_label_component(int) # aqueous # ------- int nb_aqueous() int get_id_aqueous(string) string get_label_aqueous(int) double nu_aqueous(int, int) double logk_aqueous(int) # mineral # ------- int nb_mineral() int get_id_mineral(string) string get_label_mineral(int) double nu_mineral(int, int) double logk_mineral(int) double molar_mass_mineral(int) double molar_volume_mineral(int) int nb_mineral_kinetic() int get_id_mineral_kinetic(string) string get_label_mineral_kinetic(int) double nu_mineral_kinetic(int, int) double logk_mineral_kinetic(int) double molar_mass_mineral_kinetic(int) double molar_volume_mineral_kinetic(int) # The database manager # Used to creat and modify the database cdef extern from "database/database.hpp" namespace "specmicp::database": cdef cppclass Database: # cython-cpp interface - list of methods that we can access # Database should be the only module accessible from python Database() Database(shared_ptr[DataContainer]) Database(string) except + void parse_database(string) except + shared_ptr[DataContainer] get_database() void swap_components(cmap[string, string]) void minerals_keep_only(vector[string]) bool is_valid() void remove_gas_phases() void remove_solid_phases() # The following methods are from # specmicp::database::DatabaseModule int component_label_to_id(string) int aqueous_label_to_id(string) int mineral_label_to_id(string) int mineral_kinetic_label_to_id(string) # header cdef class DatabaseManager: """ The Python database handler Use this class for checking values in the database or switching basis/dropping minerals or components... """ cdef Database *database cdef void init_database(self, shared_ptr[DataContainer] raw_db) cdef shared_ptr[DataContainer] container cdef shared_ptr[DataContainer] get_raw_db(self) cdef DataContainer* _get(self) diff --git a/cython/specmicp/database.pyx b/cython/specmicp/database.pyx index 337d8de..a2f48f9 100644 --- a/cython/specmicp/database.pyx +++ b/cython/specmicp/database.pyx @@ -1,366 +1,369 @@ -# 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: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of SpecMiCP 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 OWNER 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. +#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. from libcpp.map cimport map as cmap from libcpp.pair cimport pair from memory cimport shared_ptr from database cimport Database, DataContainer # Used to indicate that something does not exist cdef enum: no_species = -1 cdef class DatabaseManager: """ The Python database handler Use this class for checking values in the database or switching basis/dropping minerals or components... """ def __cinit__(self, bytes filepath): """filepath is the path to the database file""" if filepath: self.database = new Database( filepath) else: self.database = new Database() self.container = self.database.get_database() def __dealloc__(self): del self.database cdef void init_database(self, shared_ptr[DataContainer] raw_db): del self.database self.database = new Database(raw_db) self.container = self.database.get_database() cdef shared_ptr[DataContainer] get_raw_db(self): return self.container cdef DataContainer* _get(self): return self.container.get() def is_valid(self): return self.database.is_valid(); def remove_gas_phases(self): self.database.remove_gas_phases() def remove_solid_phases(self): self.database.remove_solid_phases() # --------- # # Component # # --------- # property nb_component: """The number of component in the database.""" def __get__(self): return self._get().nb_component() # labels and id # -------------- def component_label_to_id(self, bytes comp): """ Return the id of a component.""" cdef int ans = self.database.component_label_to_id(comp) if (ans == no_species): raise ValueError("Species : '"+comp.decode()+"' is not a component.") return ans def component_id_to_label(self, int idc): """ Return the label of a component.""" if (idc >= self.nb_component): raise ValueError("'"+str(idc)+ "' is not a valid index for a component") return bytes(self._get().get_label_component(idc)) def print_basis(self): """Print the components in the basis, with their ID""" print("The basis is :") cdef int i for i in range(self.nb_component): print(" - "+str(i)+" : "+bytes(self._get().get_label_component(i)).decode()) # basis switch # ------------ def swap_components(self, dict swapping): """Swap components in the basis swapping is a dictionnary where the keys are the labels of the components to replace and the values are the labels of the secondary species to add in the basis. Raise value errors if the labels are invalid """ cdef cmap[string,string] input_map cdef int idsp for (key, value) in swapping.items(): idsp = self.component_label_to_id(key) if (idsp == no_species): raise ValueError("'"+key.decode()+"' is not a valid component.") idsp = self.aqueous_label_to_id(value) if (idsp == no_species): raise ValueError("'"+key.decode()+ "' is not a valid secondary aqueous species.") input_map.insert(pair[string, string](key, value)) self.database.swap_components(input_map) # --------------- # # Aqueous species # # --------------- # property nb_aqueous: """The number of aqueous species in the database""" def __get__(self): return self._get().nb_aqueous() # labels and id # ------------- def aqueous_id_to_label(self, int ids): if (ids >= self.nb_aqueous): raise ValueError("'"+str(ids)+ "' is not a valid index for a secondary aqueous species") return bytes(self._get().get_label_aqueous(ids)) def aqueous_label_to_id(self, bytes aqueous): """ Return the id of a secondary aqueous species""" cdef int ans = self.database.aqueous_label_to_id(aqueous) if (ans == no_species): raise ValueError("Species : '"+aqueous.decode()+ "' is not a secondary aqueous species.") return ans def print_aqueous(self): """ Print the secondary species""" print("The secondary aqueous species are :") cdef int i for i in range(self.nb_aqueous): print(" - "+str(i)+" : "+bytes(self._get().get_label_aqueous(i)).decode()) # properties # ---------- def nu_aqueous(self, int ids, int idc): """Return stoichiometric coefficient of a secondary aqueous species""" if (ids >= self.nb_aqueous or idc >= self.nb_component): raise ValueError("Incorrect bounds") return self._get().nu_aqueous(ids, idc) def l_nu_aqueous(self, bytes aqueous, bytes component): """Return stoichiometric coefficient of a secondary aqueous species""" return self._get().nu_aqueous(self.aqueous_label_to_id(aqueous), self.component_label_to_id(component)) def logk_aqueous(self, int ids): """Return the equilibrium constant of a secondary aqueous species""" if (ids >= self.nb_aqueous): raise ValueError("Index : '"+str(ids) +"' is not valid for an aqueous species") return self._get().logk_aqueous(ids) def l_logk_aqueous(self, bytes aqueous): """Return the equilibrium constant of a secondary aqueous species""" return self._get().logk_aqueous(self.aqueous_label_to_id(aqueous)) # ------------ # # Solid phases # # ------------ # # Equilibrium # ======= property nb_mineral: """The number of mineral in the database""" def __get__(self): return self._get().nb_mineral() # labels and id # ------------- def mineral_id_to_label(self, int idm): """Return the label of a mineral.""" if (idm >= self.nb_mineral): raise ValueError("'"+str(idm)+ "' is not a valid index for a solid phase") return bytes(self._get().get_label_mineral(idm)) def mineral_label_to_id(self, bytes mineral): """ Return the id of a mineral""" ans = self.database.mineral_label_to_id(mineral) if (ans == no_species): raise ValueError("Species : '"+mineral.decode()+ "' is not a solid phase at equilibrium in the database.") return ans def print_minerals(self): """ Print the solid phases at equilibrium""" print("The solid phases at equilibrium are :") cdef int i for i in range(self.nb_mineral): print(" - "+str(i)+" : "+bytes(self._get().get_label_mineral(i)).decode()) def minerals_keep_only(self, list_mineral_to_keep): """Keep only the solid phases in 'list_mineral_to_keep'""" # we first verify that the list is valid for label in list_mineral_to_keep: self.mineral_label_to_id(label) # just check that it is not raising any error self.database.minerals_keep_only(list_mineral_to_keep) # properties # ---------- def logk_mineral(self, int idm): """Return the equilibrium constant of a solid phase""" if (idm >= self.nb_mineral): raise ValueError("Index : '"+str(idm) +"'is not valid for a solid phase") return self._get().logk_mineral(idm) def l_logk_mineral(self, bytes mineral): """Return the equilibrium constant of a solid phase""" return self._get().logk_mineral(self.mineral_label_to_id(mineral)) def nu_mineral(self, int idm, int idc): """Return stoichometric coefficient of a mineral""" if (idm >= self.nb_mineral or idc >= self.nb_component): raise ValueError("Incorrect argument, exceed bounds") return self._get().nu_mineral(idm, idc) def l_nu_mineral(self, bytes mineral, bytes component): """Return stoichometric coefficient of a mineral""" return self._get().nu_mineral(self.mineral_label_to_id(mineral), self.component_label_to_id(component)) def molar_mass_mineral(self, int idm): """Return the molar mass (kg/mol) of mineral 'idm'""" if (idm >= self.nb_mineral): raise ValueError("Index : '"+str(idm) +"'is not valid for a solid phase") return self._get().molar_mass_mineral(idm) def l_molar_mass_mineral(self, bytes mineral): """Return the molar mass (kg/mol) of 'mineral'""" return self.molar_mass_mineral(self.mineral_label_to_id(mineral)) def molar_volume_mineral(self, int idm): """Return the molar volume (m^3/mol) of mineral 'idm'""" if (idm >= self.nb_mineral): raise ValueError("Index : '"+str(idm) +"'is not valid for a solid phase") return self._get().molar_volume_mineral(idm) def l_molar_volume_mineral(self, bytes mineral): """Return the molar volume (m^3/mol) of 'mineral'""" return self.molar_volume_mineral(self.mineral_label_to_id(mineral)) def density_mineral(self, int idm): """Return the density (kg/m^3) of a mineral 'idm'""" return (self._get().molar_mass_mineral(idm) / self._get().molar_volume_mineral(idm)) def l_density_mineral(self, bytes mineral): """Return the density (kg/m^3) of a mineral 'idm'""" return self.density_mineral( self.mineral_label_to_id(mineral)) # Kinetic # =========== property nb_mineral_kinetic: """The number of mineral governed by kinetics in the database""" def __get__(self): return self._get().nb_mineral_kinetic() # labels and id # ------------- def mineral_kinetic_id_to_label(self, int idm): """Return the label of a mineral.""" if (idm >= self.nb_mineral_kinetic): raise ValueError("'"+str(idm)+ "' is not a valid index for a kinetic solid phase") return bytes(self._get().get_label_mineral_kinetic(idm)) def mineral_kinetic_label_to_id(self, bytes mineral): """ Return the id of a mineral governed by kinetics""" ans = self.database.mineral_kinetic_label_to_id(mineral) if (ans == no_species): raise ValueError("Species : '"+mineral.decode()+ "' is not a solid phase at equilibrium in the database.") return ans def print_minerals_kinetic(self): """ Print the solid phases governed by kinetic""" print("The solid phases governed by kinetics law are :") cdef int i for i in range(self.nb_mineral_kinetic): print(" - "+str(i)+" : "+bytes(self._get().get_label_mineral_kinetic(i)).decode()) # properties # ---------- def logk_mineral_kinetic(self, int idm): """Return the equilibrium constant of a solid phase""" if (idm >= self.nb_mineral_kinetic): raise ValueError("Index : '"+str(idm) +"'is not valid for a solid phase") return self._get().logk_mineral_kinetic(idm) def l_logk_mineral_kinetic(self, bytes mineral): """Return the equilibrium constant of a solid phase""" return self._get().logk_mineral_kinetic( self.mineral_kinetic_label_to_id(mineral)) def nu_mineral_kinetic(self, int idm, int idc): """Return stoichometric coefficient of a mineral""" if (idm >= self.nb_mineral_kinetic or idc >= self.nb_component): raise ValueError("Incorrect argument, exceed bounds") return self._get().nu_mineral_kinetic(idm, idc) def l_nu_mineral_kinetic(self, bytes mineral, bytes component): """Return stoichometric coefficient of a mineral""" return self._get().nu_mineral_kinetic( self.mineral_kinetic_label_to_id(mineral), self.component_label_to_id(component)) def molar_mass_mineral_kinetic(self, int idm): """Return the molar mass (kg/mol) of mineral 'idm'""" if (idm >= self.nb_mineral_kinetic): raise ValueError("Index : '"+str(idm) +"'is not valid for a solid phase") return self._get().molar_mass_mineral_kinetic(idm) def l_molar_mass_mineral_kinetic(self, bytes mineral): """Return the molar mass (kg/mol) of 'mineral'""" return self.molar_mass_mineral_kinetic( self.mineral_kinetic_label_to_id(mineral)) def molar_volume_mineral_kinetic(self, int idm): """Return the molar volume (m^3/mol) of mineral 'idm'""" if (idm >= self.nb_mineral_kinetic): raise ValueError("Index : '"+str(idm) +"'is not valid for a solid phase") return self._get().molar_volume_mineral_kinetic(idm) def l_molar_volume_mineral_kinetic(self, bytes mineral): """Return the molar volume (m^3/mol) of 'mineral'""" return self.molar_volume_mineral_kinetic( self.mineral_kinetic_label_to_id(mineral)) def density_mineral_kinetic(self, int idm): """Return the density (kg/m^3) of a mineral 'idm'""" return (self._get().molar_mass_mineral_kinetic(idm) / self._get().molar_volume_mineral_kinetic(idm)) def l_density_mineral_kinetic(self, bytes mineral): """Return the density (kg/m^3) of a mineral 'idm'""" return self.density_mineral_kinetic( - self.mineral_kinetic_label_to_id(mineral)) \ No newline at end of file + self.mineral_kinetic_label_to_id(mineral)) diff --git a/cython/specmicp/init_log.hpp b/cython/specmicp/init_log.hpp index a1e47be..ba11b17 100644 --- a/cython/specmicp/init_log.hpp +++ b/cython/specmicp/init_log.hpp @@ -1,38 +1,70 @@ +/*------------------------------------------------------------------------------- + +Copyright (c) 2014,2015 F. 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. + +-----------------------------------------------------------------------------*/ + #ifndef SPECMICP_CYTHON_INITLOG_HPP #define SPECMICP_CYTHON_INITLOG_HPP #include "utils/log.hpp" #include namespace specmicp { inline void init_logger_cout_debug() { init_logger(&std::cout, specmicp::logger::Debug); } inline void init_logger_cout_warning() { init_logger(&std::cout, specmicp::logger::Warning); } inline void init_logger_cout_error() { init_logger(&std::cout, specmicp::logger::Error); } inline void init_logger_cerr_debug() { init_logger(&std::cerr, specmicp::logger::Debug); } inline void init_logger_cerr_warning() { init_logger(&std::cerr, specmicp::logger::Warning); } inline void init_logger_cerr_error() { init_logger(&std::cerr, specmicp::logger::Error); } } // end namespace specmicp #endif // SPECMICP_CYTHON_INITLOG_HPP diff --git a/cython/specmicp/is_solver_successful.hpp b/cython/specmicp/is_solver_successful.hpp index da244fc..e4ed6f4 100644 --- a/cython/specmicp/is_solver_successful.hpp +++ b/cython/specmicp/is_solver_successful.hpp @@ -1,27 +1,60 @@ +/*------------------------------------------------------------------------------- + +Copyright (c) 2014,2015 F. 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. + +-----------------------------------------------------------------------------*/ + + #ifndef SPECMICP_CYTHON_SUCCESSFUL_SOLVER #define SPECMICP_CYTHON_SUCCESSFUL_SOLVER #include "micpsolver/micpsolver_structs.hpp" #include // just for cython namespace specmicp { namespace micpsolver { //! \brief Return true if the solver is successful inline bool is_solver_successful(MiCPSolverReturnCode return_code) { return (return_code > MiCPSolverReturnCode::Success); } //! \brief Cast the return code to an int inline std::underlying_type::type cast_return_code(MiCPSolverReturnCode return_code) { return static_cast::type>(return_code); } } // end namespace micpsolver } // end namespace specmicp #endif //SPECMICP_CYTHON_SUCCESSFUL_SOLVER diff --git a/cython/specmicp/logger.pxd b/cython/specmicp/logger.pxd index d94638f..155e2d2 100644 --- a/cython/specmicp/logger.pxd +++ b/cython/specmicp/logger.pxd @@ -1,32 +1,35 @@ -# 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: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of the Princeton University 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 OWNER 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. +#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. cdef extern from "init_log.hpp" namespace "specmicp": void c_init_looger_cout_debug "specmicp::init_logger_cout_debug" () void c_init_logger_cout_warning "specmicp::init_logger_cout_warning" () void c_init_logger_cout_error "specmicp::init_logger_cout_error" () void c_init_logger_cerr_debug "specmicp::init_logger_cerr_debug" () void c_init_logger_cerr_warning "specmicp::init_logger_cerr_warning" () - void c_init_logger_cerr_error "specmicp::init_logger_cerr_error" () \ No newline at end of file + void c_init_logger_cerr_error "specmicp::init_logger_cerr_error" () diff --git a/cython/specmicp/logger.pyx b/cython/specmicp/logger.pyx index 58db61a..0335e74 100644 --- a/cython/specmicp/logger.pyx +++ b/cython/specmicp/logger.pyx @@ -1,44 +1,47 @@ -# 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: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of the Princeton University 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 OWNER 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. +#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. cimport logger as lg def init_logger_cout_debug(): lg.c_init_logger_cout_debug() def init_logger_cout_warning(): lg.c_init_logger_cout_warning() def init_logger_cout_error(): lg.c_init_logger_cout_error() def init_logger_cerr_debug(): lg.c_init_logger_cerr_debug() def init_logger_cerr_warning(): lg.c_init_logger_cerr_warning() def init_logger_cerr_error(): - lg.c_init_logger_cerr_error() \ No newline at end of file + lg.c_init_logger_cerr_error() diff --git a/cython/specmicp/set_units.hpp b/cython/specmicp/set_units.hpp index 511d099..9123954 100644 --- a/cython/specmicp/set_units.hpp +++ b/cython/specmicp/set_units.hpp @@ -1,16 +1,48 @@ +/*------------------------------------------------------------------------------- + +Copyright (c) 2014,2015 F. 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. + +-----------------------------------------------------------------------------*/ + #ifndef SPECMICP_CYTHON_SETUNITS #define SPECMICP_CYTHON_SETUNITS #include "physics/units.hpp" namespace specmicp { namespace units { inline void set_meter(LengthUnit& length) {length = LengthUnit::meter;} inline void set_decimeter(LengthUnit& length) {length = LengthUnit::decimeter;} inline void set_centimeter(LengthUnit& length) {length = LengthUnit::centimeter;} } // end namespace units } // end namespace specmicp #endif diff --git a/cython/specmicp/solution.pxd b/cython/specmicp/solution.pxd index 9084631..5e90ca1 100644 --- a/cython/specmicp/solution.pxd +++ b/cython/specmicp/solution.pxd @@ -1,99 +1,101 @@ -# 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: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of SpecMiCP 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 OWNER 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. - +#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. from libcpp cimport bool from memory cimport shared_ptr from database cimport DataContainer from units cimport UnitsSet from eigen cimport VectorXd # The solution # ------------- # note: access is restrictive since the user should use # the extractor class to acces the data cdef extern from "specmicp/adimensional/adimensional_system_solution.hpp" namespace "specmicp": cdef cppclass AdimensionalSystemSolution: AdimensionalSystemSolution() AdimensionalSystemSolution(const AdimensionalSystemSolution&) bool is_valid # The solution extractor # ---------------------- cdef extern from "specmicp/adimensional/adimensional_system_solution_extractor.hpp" namespace "specmicp": cdef cppclass AdimensionalSystemSolutionExtractor: AdimensionalSystemSolutionExtractor( const AdimensionalSystemSolution&, shared_ptr[DataContainer], UnitsSet ) double volume_fraction_water() double density_water() double saturation_water() double saturation_gas_phase() double porosity() double pE() double Eh() double molality_component(int) double activity_component(int) double volume_fraction_mineral(int) double mole_concentration_mineral(int) double mass_concentration_mineral(int) double saturation_index(int) double free_surface_concentration() double ionic_strength() double pH() double molality_aqueous(int) double activity_aqueous(int) double fugacity_gas(int) double molality_sorbed_species(int) double total_aqueous_concentration(int) double total_solid_concentration(int) double total_immobile_concentration(int) double volume_fraction_inert() VectorXd get_main_variables() shared_ptr[DataContainer] get_database() # Cython wrapper # -------------- # the extractor only contains a reference to the solution # so we need to store the solution also cdef class SpecMiCPSolution: cdef AdimensionalSystemSolution* solution cdef AdimensionalSystemSolutionExtractor* extractor cdef void set_solution( self, const AdimensionalSystemSolution& solution, shared_ptr[DataContainer] database, UnitsSet units_set ) cdef AdimensionalSystemSolution* _get(self) cdef VectorXd get_main_variables(self) diff --git a/cython/specmicp/solution.pyx b/cython/specmicp/solution.pyx index 37e49c7..0e5b0eb 100644 --- a/cython/specmicp/solution.pyx +++ b/cython/specmicp/solution.pyx @@ -1,161 +1,162 @@ -# 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: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of SpecMiCP 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 OWNER 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. - - +#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. from solution cimport SpecMiCPSolution from cython.operator cimport dereference from specmicp.database cimport DataContainer, DatabaseManager from units cimport UnitsSet cdef class SpecMiCPSolution: """Contain a solution from the SpecMiCP solver It correspond to the AdimensionalSystemSolutionExtractor of the c++ API This class should only be created by the SpecMiCP solver. """ def __dealloc__(self): if self.extractor: del self.extractor if self.solution: del self.solution cdef void set_solution( self, const AdimensionalSystemSolution& solution, shared_ptr[DataContainer] database, UnitsSet units_set ): """Set the solution -- only callable from cython code !""" self.solution = new AdimensionalSystemSolution(solution) self.extractor = new AdimensionalSystemSolutionExtractor( dereference(self.solution), database, units_set ) cdef AdimensionalSystemSolution* _get(self): """Return the solution, only callable from cython code""" return self.solution cdef VectorXd get_main_variables(self): """Return the vector of main variables""" return self.extractor.get_main_variables() # water and gas volume fraction # ----------------------------- def volume_fraction_water(self): """Return the volume fraction of water""" return self.extractor.volume_fraction_water() def density_water(self): """Return the density of water (in the correct units)""" return self.extractor.density_water() def porosity(self): """Return the porosity""" return self.extractor.porosity() def saturation_water(self): """Return the saturation of the liquid phase""" return self.extractor.saturation_water() def saturation_gas_phase(self): """Return the saturation of the gas phase""" return self.extractor.saturation_gas_phase() def volume_fraction_inert(self): """Return the volume fraction of inert phases""" return self.extractor.volume_fraction_inert() # solution properties # ------------------- def pE(self): """Return pE""" return self.extractor.pE() def Eh(self): """Return Eh""" return self.extractor.Eh() def pH(self): """Return the pH of the solution""" return self.extractor.pH() def ionic_strength(self): """Return the ionic strength of the solution""" return self.extractor.ionic_strength() # components def molality_component(self, index): """Return molality of component 'index'""" return self.extractor.molality_component(index) def activity_component(self, index): """Return the molality of component 'index'""" return self.extractor.activity_component(index) # minerals # -------- def volume_fraction_mineral(self, index): """Return the volume fraction of mineral 'index'""" return self.extractor.volume_fraction_mineral(index) def mole_concentration_mineral(self, index): """Return the concentration (mol/V) of mineral 'index'""" return self.extractor.mole_concentration_mineral(index) def mass_concentration_mineral(self, index): """Return the concentration (M/V) of mineral 'index'""" return self.extractor.mass_concentration_mineral(index) def saturation_index(self, index): """Return the saturation index of mineral 'index'""" return self.extractor.saturation_index(index) # aqueous species # --------------- def molality_aqueous(self, index): """Return the molality of aqueous 'index'""" return self.extractor.molality_aqueous(index) def activity_aqueous(self, index): """Return the activity of aqueous 'index'""" return self.extractor.activity_aqueous(index) # gas # --- def fugacity_gas(self, index): """Return the fugacity of gas 'index'""" return self.extractor.fugacity_gas(index) # sorption model # -------------- def concentration_free_surface_sites(self): """Return the concentration of free surface sites""" return self.extractor.free_surface_concentration() def molality_sorbed_species(self, index): """Return the molality of sorbed_species 'index'""" return self.extractor.molality_sorbed_species(index) # total concentrations # -------------------- def total_aqueous_concentration(self, index): """Return the total aqueous concentration of component 'index'""" return self.extractor.total_aqueous_concentration(index) def total_solid_concentration(self, index): """Return the total solid concentration of component 'index'""" return self.extractor.total_solid_concentration(index) def total_immobile_concentration(self, index): """Return the total immobile (solid+sorbed) concentration of component 'index'""" return self.extractor.total_immobile_concentration(index) def get_database(self): """Return the database""" db = DatabaseManager(b"") db.init_database(self.extractor.get_database()) - return db \ No newline at end of file + return db diff --git a/cython/specmicp/solver.pxd b/cython/specmicp/solver.pxd index a93fe75..71d3ad9 100644 --- a/cython/specmicp/solver.pxd +++ b/cython/specmicp/solver.pxd @@ -1,43 +1,71 @@ +#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. + from libcpp.map cimport map as cmap from libcpp cimport bool from libcpp.string cimport string from eigen cimport VectorXd from memory cimport shared_ptr from database cimport DatabaseManager, DataContainer from solution cimport AdimensionalSystemSolution from constraints cimport AdimensionalSystemConstraints from solver_options cimport MiCPPerformance, AdimensionalSystemSolverOptions, AdimensionalSystemOptions, MiCPSolverOptions # The SpecMiCP Solver # ------------------- cdef extern from "specmicp/adimensional/adimensional_system_solver.hpp" namespace "specmicp": cdef cppclass AdimensionalSystemSolver: AdimensionalSystemSolver( shared_ptr[DataContainer], const AdimensionalSystemConstraints& ) AdimensionalSystemSolver( shared_ptr[DataContainer], const AdimensionalSystemConstraints&, const AdimensionalSystemSolution& ) MiCPPerformance solve(VectorXd&, bool) nogil, AdimensionalSystemSolution get_raw_solution(VectorXd&) void run_pcfm(VectorXd&) void initialise_variables(VectorXd&, double, cmap[string, double]) void initialise_variables(VectorXd&, double, double) AdimensionalSystemSolverOptions& get_options() nogil # read-only # Wrapper to the solver # --------------------- cdef class SpecMiCPSolver: cdef DatabaseManager database cdef AdimensionalSystemSolver* solver cdef VectorXd* variables cdef AdimensionalSystemSolverOptions* get_options(self) nogil cdef AdimensionalSystemOptions* get_system_options(self) nogil cdef MiCPSolverOptions* get_micpsolver_options(self) nogil diff --git a/cython/specmicp/solver.pyx b/cython/specmicp/solver.pyx index e7077f0..5b4119b 100644 --- a/cython/specmicp/solver.pyx +++ b/cython/specmicp/solver.pyx @@ -1,222 +1,251 @@ +#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. + + from libcpp.map cimport map as cmap from libcpp.string cimport string from libcpp.utility cimport pair from solver cimport SpecMiCPSolver, AdimensionalSystemSolver from database cimport DatabaseManager from constraints cimport SpecMiCPConstraints, AdimensionalSystemConstraints from solver_options cimport MiCPSolverReturnCode, MiCPPerformance, is_solver_successful from solution cimport SpecMiCPSolution cimport units from cython.operator cimport dereference cdef class SpecMiCPSolver: def __cinit__( self, DatabaseManager database not None, SpecMiCPConstraints constraints not None, SpecMiCPSolution solution ): """Initialisation""" self.database = database if solution is None: self.solver = new AdimensionalSystemSolver( database.get_raw_db(), dereference(constraints._get()) ) else: self.solver = new AdimensionalSystemSolver( database.get_raw_db(), dereference(constraints._get()), dereference(solution._get()) ) self.variables = new VectorXd(solution.get_main_variables()) def __dealloc__(self): if self.solver: del self.solver if self.variables: del self.variables cdef AdimensionalSystemSolverOptions* get_options(self) nogil: """Return the options""" return &(self.solver.get_options()) cdef AdimensionalSystemOptions* get_system_options(self) nogil: """Return the options of the SpecMiCP program""" return &(self.solver.get_options().system_options) cdef MiCPSolverOptions* get_micpsolver_options(self) nogil: """Return the MiCPSolver options""" return &(self.solver.get_options().solver_options) def get_solution(self): """Return the solution""" if not self.solver: raise RuntimeError("No solver") solution = SpecMiCPSolution() solution.set_solution( self.solver.get_raw_solution(dereference(self.variables)), self.database.get_raw_db(), self.solver.get_options().units_set ) return solution def initialize_variables(self, water_saturation, log_molalities_component): """Initialize the variables The log_molalities_component can be - a double : the initial value gor the log_10 of the molalities - a dictionnary {"label component": log_molalities} """ cdef cmap[string, double] map_comp if not self.variables: self.variables = new VectorXd() if hasattr(log_molalities_component, "items"): for (key, value) in log_molalities_component.items(): map_comp.insert(pair[string, double](key, value)) self.solver.initialise_variables(dereference(self.variables), float(water_saturation), map_comp) else: self.solver.initialise_variables(dereference(self.variables), float(water_saturation), float(log_molalities_component) ) def solve(self, initialize=True): """Solve the problem""" cdef MiCPPerformance perf cdef bool init = initialize if not self.variables: self.variables = new VectorXd() with nogil: perf = self.solver.solve(dereference(self.variables), init) if not is_solver_successful(perf.return_code): raise RuntimeError("Error - the system cannot be solved.") # Options # ======= # adimensionalsolver options # -------------------------- def set_length_unit(self, length_unit): """Set the length unit""" if length_unit in ("m", "meter"): units.set_meter(self.get_options().units_set.length) elif length_unit in ("dm", "decimeter"): units.set_decimeter(self.get_options().units_set.length) elif length_unit in ("cm", "centimeter"): units.set_centimeter(self.get_options().units_set.length) else: raise ValueError("Unit : " + str(length_unit) + "is not recognized") def enable_restart(self): """Allow the solve to be restarted in case of failure""" self.get_options().allow_restart = True def disable_restart(self): """Failure to solve the problem is critical""" self.get_options().allow_restart = False def enable_pcfm(self): """Enable the positive continuous fraction method""" self.get_options().use_pcfm = True def disable_pcfm(self): """Disable the positive continuous fraction method""" self.get_options().use_pcfm = False # System options # --------------- def enable_non_ideality(self): """Enable the nonideality model of the aqueous solution""" self.get_system_options().non_ideality = True def disable_non_ideality(self): """Disable the nonideality model of the aqueous solution""" self.get_system_options().non_ideality = False def set_non_ideality_max_iterations(self, max_iterations): """Set the maximum iterations allowed for the non ideality model""" self.get_system_options().non_ideality_max_iter = int(max_iterations) def set_non_ideality_tolerance(self, tolerance): """Set the tolerance for the non ideality model""" self.get_system_options().non_ideality_tolerance = float(tolerance) def set_non_ideality_start_factor(self, start_factor): """A factor that governs the non-ideality computation""" self.get_system_options().start_non_ideality_computation = float(start_factor) def set_under_relaxation_factor(self, factor): """Set the under relaxtion factor """ self.get_system_options().under_relaxation_factor = float(factor) def set_restart_concentration(self, log_molality): """Set the molality used to re-initialize the problem in case of failure""" self.get_system_options().restart_concentration = float(log_molality) def set_new_component_concentration(self, log_molality): """Set the concentration for a new component""" self.get_system_options().new_component_concentration = float(log_molality) def set_cutoff_total_concentrations(self, cutoff): """Set the cutoff for the total concentrations""" self.get_system_options().cutoff_total_concentration = float(cutoff) # MiCPSolver options # ------------------ def set_tolerance(self, residuals_tol): """Set the residuals tolerance""" self.get_micpsolver_options().set_tolerance(residuals_tol) def set_tolerances(self, residuals_tol, step_tol): """"Set the residuals and the step tolerances""" self.get_micpsolver_options().set_tolerance(residuals_tol, step_tol) def set_maximum_iterations(self, max_iterations): """Set the maximum number of operations""" self.get_micpsolver_options().set_maximum_iterations(max_iterations) def set_maximum_step_length(self, max_step_length, max_iter_at_max_length=None): """Set the maximum step length""" if max_iter_at_max_length is not None: self.get_micpsolver_options().set_maximum_step_length( max_step_length, max_iter_at_max_length) else: self.get_micpsolver_options().set_maximum_step_length( max_step_length) def disable_descent_direction(self): """Disable the descent direction condition""" self.get_micpsolver_options().disable_descent_direction() def enable_descent_direction(self, factor, power): """Enable the descent direction condition""" self.get_micpsolver_options().enable_descent_direction(factor, power) def disable_condition_check(self): """Disable the descent direction""" self.get_micpsolver_options().disable_condition_check() def enable_condition_check(self, threshold): """Enable the condition check""" self.get_micpsolver_options().enable_condition_check(threshold) def disable_non_monotone_linesearch(self): """Disable the non monotone linesearch""" self.get_micpsolver_options().disable_non_monotone_linesearch() def enable_non_monotone_linesearch(self): """Enable the non monotone linesearch""" self.get_micpsolver_options().enable_non_monotone_linesearch() def disable_jacobian_scaling(self): """Disable the Jacobian scaling""" self.get_micpsolver_options().disable_scaling() def enable_jacobian_scaling(self): """Enable the Jacobian scaling""" self.get_micpsolver_options().enable_scaling() def disable_crashing(self): """Disable the crashing""" self.get_micpsolver_options().disable_crashing() def enable_crashing(self): """Enable the crashing""" self.get_micpsolver_options().enable_crashing() diff --git a/cython/specmicp/solver_options.pxd b/cython/specmicp/solver_options.pxd index 3599695..e3ecc86 100644 --- a/cython/specmicp/solver_options.pxd +++ b/cython/specmicp/solver_options.pxd @@ -1,120 +1,123 @@ -# 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: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of the Princeton University 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 OWNER 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. +#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. from libcpp cimport bool from units cimport UnitsSet cdef extern from "micpsolver/micpsolver_structs.hpp" namespace "specmicp::micpsolver": cdef cppclass MiCPSolverOptions: MiCPSolverOptions() int max_iter double fvectol double steptol double condition_limit double penalization_factor double maxstep int maxiter_maxstep double factor_descent_condition double power_descent_condition bool use_crashing double coeff_accept_newton_step bool use_scaling double factor_gradient_search_direction double projection_min_variable double threshold_stationary_point int max_factorization_step void set_maximum_iterations(int) void set_maximum_step_length(double) void set_maximum_step_length(double, int) void disable_descent_direction() void enable_descent_direction(double, double) void disable_condition_check() void enable_condition_check(double) void disable_non_monotone_linesearch() void enable_scaling() void disable_scaling() void enable_crashing() void disable_crashing() void enable_non_monotone_linesearch() void set_tolerance(double) void set_tolerance(double, double) cdef enum MiCPSolverReturnCode: LolItsNotSupposedToHappen "specmicp::micpsolver::MiCPSolverReturnCode::LolItsNotSupposedToHappen" MaxStepTakenTooManyTimes "specmicp::micpsolver::MiCPSolverReturnCode::MaxStepTakenTooManyTimes" FailedToSolveLinearSystem "specmicp::micpsolver::MiCPSolverReturnCode::FailedToSolveLinearSystem" MaxIterations "specmicp::micpsolver::MiCPSolverReturnCode::MaxIterations" StationaryPoint "specmicp::micpsolver::MiCPSolverReturnCode::StationaryPoint" NotConvergedYet "specmicp::micpsolver::MiCPSolverReturnCode::NotConvergedYet" Success "specmicp::micpsolver::MiCPSolverReturnCode::Success" ResidualMinimized "specmicp::micpsolver::MiCPSolverReturnCode::ResidualMinimized" ErrorMinimized "specmicp::micpsolver::MiCPSolverReturnCode::ErrorMinimized" cdef cppclass MiCPPerformance: MiCPPerformance() int nb_call_residuals int nb_call_jacobian int nb_factorization int nb_gradient_step int nb_crashing_iterations int nb_iterations bool max_taken int nb_max_taken int nb_consecutive_max_taken MiCPSolverReturnCode return_code cdef enum NCPfunction: penFB_function "specmicp::micpsolver::NCPfunction::penalizedFB" min_function "specmicp::micpsolver::NCPfunction::min" cdef extern from "is_solver_successful.hpp" namespace "specmicp::micpsolver": cdef bool is_solver_successful(MiCPSolverReturnCode) cdef int cast_return_code(MiCPSolverReturnCode) cdef extern from "specmicp/adimensional/adimensional_system_structs.hpp" namespace "specmicp": cdef cppclass AdimensionalSystemOptions: bool non_ideality int non_ideality_max_iter double scaling_electron double non_ideality_tolerance double under_relaxation_factor double restart_concentration double new_component_concentration double start_non_ideality_computation double cutoff_total_concentration cdef extern from "specmicp/adimensional/adimensional_system_solver_structs.hpp" namespace "specmicp": cdef cppclass AdimensionalSystemSolverOptions: AdimensionalSystemSolverOptions() MiCPSolverOptions solver_options AdimensionalSystemOptions system_options UnitsSet units_set bool allow_restart bool use_pcfm bool force_pcfm diff --git a/cython/specmicp/units.pxd b/cython/specmicp/units.pxd index ee1006f..146421a 100644 --- a/cython/specmicp/units.pxd +++ b/cython/specmicp/units.pxd @@ -1,47 +1,49 @@ -# 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: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of SpecMiCP 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 OWNER 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. - +#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. cdef extern from "physics/units.hpp" namespace "specmicp::units": cdef enum LengthUnit: meter "specmicp::units::LengthUnit::meter" decimeter "specmicp::units::LengthUnit::decimeter" centimeter "specmicp::units::LengthUnit::centimeter" cdef enum MassUnit: kilogram "specmicp::units::MassUnit::kilogram" gram "specmicp::units::MassUnit::gram" cdef cppclass UnitsSet: UnitsSet() MassUnit mass LengthUnit length # These are the function that allows us to overcome the "enum class" cython incompatibility cdef extern from "set_units.hpp" namespace "specmicp::units": void set_meter(LengthUnit&) void set_decimeter(LengthUnit&) - void set_centimeter(LengthUnit&) \ No newline at end of file + void set_centimeter(LengthUnit&) diff --git a/examples/reactmicp/saturated_react/carbonation.cpp b/examples/reactmicp/saturated_react/carbonation.cpp index e06a764..845ff19 100644 --- a/examples/reactmicp/saturated_react/carbonation.cpp +++ b/examples/reactmicp/saturated_react/carbonation.cpp @@ -1,864 +1,835 @@ -/*------------------------------------------------------- - -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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University 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 OWNER 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. - ----------------------------------------------------------*/ - // ============================================ // Saturated carbonation of a cement past // ============================================= // This file can be used to learn how to use ReactMiCP // Include ReactMiCP #include "reactmicp.hpp" // Other includes that would be needed later : #include #include "physics/laws.hpp" #include "utils/timer.hpp" #include #include #include // we use the following namespaces using namespace specmicp; using namespace reactmicp; using namespace reactmicp::systems; using namespace specmicp::reactmicp::systems::satdiff; using namespace reactmicp::solver; // We declare some functions that we will be using : // Database // ======== // Parse and Prepare the database RawDatabasePtr get_database(const std::string& path_to_database); // Boundary and initial conditions // =============================== // Return the chemistry constraints for the inital condition AdimensionalSystemConstraints get_cement_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set); // return the chemistry constraints for the boundary condition AdimensionalSystemConstraints get_bc_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set); Vector initial_compo(const Vector& publi); void compo_from_oxyde(Vector& compo_oxyde, Vector& compo_species); // The mesh // ======== // There is two version // a uniform mesh mesh::Mesh1DPtr get_mesh(scalar_t dx); // and a non uniform mesh mesh::Mesh1DPtr get_mesh(); // Options // ======= // Speciation solver options AdimensionalSystemSolverOptions get_specmicp_options(); // Transport options void set_transport_options(dfpmsolver::ParabolicDriverOptions& transport_options); // Reactive Solver options void set_reactive_solver_options(reactmicp::solver::ReactiveTransportOptions& reactive_options); // Upscaling // ========= // Upscaling is the stagger in charge of finding the porosity and transport properties // This is a class that is dependant on the problem to solve and should be defined by the user // The following class is an example on how to define such a class // The Upscaling class should inherit from UpscalingStaggerBase class CarboUspcaling: public solver::UpscalingStaggerBase { public: // Initiation // This is not call automatically so can be adjusted by the user CarboUspcaling(RawDatabasePtr the_database, units::UnitsSet the_units): m_data(the_database), m_units_set(the_units), m_dt(HUGE_VAL) { } // Initialize the stagger at the beginning of the computation // The porosity and transport properties should be initialized here void initialize(VariablesBasePtr var) { SaturatedVariablesPtr true_var = cast_var_from_base(var); true_var->upscaling_variables().setZero(); for (index_t node=0; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); } } // Initialize the stagger at the beginning of a timestep // Typically do nothing but erase the "dot" variable (velocity such as the vel_porosity) void initialize_timestep(scalar_t dt, VariablesBasePtr var) { SaturatedVariablesPtr true_var = cast_var_from_base(var); m_dt = dt; for (index_t node=1; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); true_var->vel_porosity(node) = 0.0; } } //! This is the main function called during a timestep StaggerReturnCode restart_timestep(VariablesBasePtr var) { SaturatedVariablesPtr true_var = cast_var_from_base(var); for (index_t node=1; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); } return StaggerReturnCode::ResidualMinimized; // This is the value that should be returned if everything is ok } // A function that return the diffusion coefficient when porosity is equal to 'porosity' scalar_t coeff_diffusion_law(scalar_t porosity) { static constexpr scalar_t de_0 = 2.726e-12; //1e-11; static constexpr scalar_t factor = 1e4; static constexpr scalar_t porosity_r = 0.02; const scalar_t ratio = ((porosity - porosity_r)/(0.25 - porosity_r)); const scalar_t d_e = factor*de_0*std::pow(ratio, 3.32); return std::min(d_e, 1e4*1e-10); } // Compute the upscaling for 'node' void upscaling_one_node(index_t node, SaturatedVariablesPtr true_var) { // AdimensionalSystemSolutionExtractor is the class to use to // extract information from a SpecMiCP solution // To obtain correct information the correct units must be used AdimensionalSystemSolutionExtractor extractor(true_var->equilibrium_solution(node), m_data, m_units_set); // We can obtain the porosity very easily : scalar_t porosity = extractor.porosity(); true_var->vel_porosity(node) += (porosity - true_var->porosity(node))/m_dt; true_var->porosity(node) = porosity; true_var->diffusion_coefficient(node) = coeff_diffusion_law(porosity); } private: RawDatabasePtr m_data; units::UnitsSet m_units_set; index_t m_id_cshj; scalar_t m_initial_sat_cshj; scalar_t m_dt; }; // ============== // Output // ============== // Many information is generated throughout a computation and we can't save everything // The reactmicp runner can call a function to output the desired information // Here the output function is a member function for convenience class OutputPolicy { public: // Initialise the output // SimulationInformation contain basic information from the simulation OutputPolicy(const SimulationInformation& simul_info, mesh::Mesh1DPtr the_mesh, RawDatabasePtr the_database, units::UnitsSet the_units): m_mesh(the_mesh), m_database(the_database), m_units(the_units) { // Open the files // Save the pH out_c_ph.open(simul_info.complete_filepath("ph", suffix)); // Save the total aqueous concentration of HCO3[-] out_c_hco3.open(simul_info.complete_filepath("c_hco3", suffix)); // save the total solid concentration of s_ca out_s_ca.open(simul_info.complete_filepath("s_ca", suffix)); // Save the volume fraction of calcite out_calcite.open(simul_info.complete_filepath("calcite", suffix)); // Save the porosity out_poro.open(simul_info.complete_filepath("poro", suffix)); // save useful indices from the database m_id_hco3 = m_database->get_id_component("HCO3[-]"); m_id_ca = m_database->get_id_component("Ca[2+]"); m_id_calcite = m_database->get_id_mineral("Calcite"); } void output(scalar_t time, VariablesBasePtr variables) { SaturatedVariablesPtr true_var = cast_var_from_base(variables); out_c_ph << time; out_c_hco3 << time; out_s_ca << time; out_calcite << time; out_poro << time; for (index_t node: m_mesh->range_nodes()) { // Again AdimensionalSystemSolutionExtractor is used to obtain information about the speciation system AdimensionalSystemSolutionExtractor extractor(true_var ->equilibrium_solution(node), m_database, m_units); out_c_ph << "\t" << extractor.pH(); out_c_hco3 << "\t" << true_var->aqueous_concentration(node, m_id_hco3); out_s_ca << "\t" << true_var->solid_concentration(node, m_id_ca); out_calcite << "\t" << extractor.volume_fraction_mineral(m_id_calcite); out_poro << "\t" << extractor.porosity(); } out_c_hco3 << std::endl; out_c_ph << std::endl; out_s_ca << std::endl; out_calcite << std::endl; out_poro << std::endl; } private: mesh::Mesh1DPtr m_mesh; RawDatabasePtr m_database; units::UnitsSet m_units; std::string suffix { "dat" }; std::ofstream out_c_ph; std::ofstream out_c_hco3; std::ofstream out_s_ca; std::ofstream out_calcite; std::ofstream out_poro; index_t m_id_hco3; index_t m_id_ca; index_t m_id_calcite; }; // =================== // MAIN // =================== int main() { // initialize eigen // This is needed if OpenMP is used Eigen::initParallel(); // Setup the log // The output will be on cerr specmicp::logger::ErrFile::stream() = &std::cerr; // And only Warning and error messages will be printed specmicp::stdlog::ReportLevel() = specmicp::logger::Warning; // The database // ------------- // Obtain the database RawDatabasePtr the_database = get_database("../data/cemdata_specmicp.js"); // SpecMiCP options // ---------------- // Set the options AdimensionalSystemSolverOptions specmicp_options = get_specmicp_options(); units::UnitsSet units_set = specmicp_options.units_set; // The mesh // -------- // Obtain the mesh mesh::Mesh1DPtr the_mesh = get_mesh(0.0050); // uniform //mesh::Mesh1DPtr the_mesh = get_mesh(); // non uniform index_t nb_nodes = the_mesh->nb_nodes(); // just boilerplate to make things easier // Print the mesh io::print_mesh("out_carbo_mesh.dat", the_mesh, units::LengthUnit::centimeter); // Initial and boundary conditions // -------------------------------- // Obtain the initial constraints // Note : the database is modified at this point // Only the relevant components are kept at this point AdimensionalSystemConstraints cement_constraints = get_cement_initial_constraints(the_database, units_set); // Obtain the initial condition AdimensionalSystemSolution cement_solution = solve_equilibrium( the_database, cement_constraints, specmicp_options); // Just to check that everything is ok ! AdimensionalSystemSolutionExtractor extractor(cement_solution, the_database, units_set); std::cout << "Porosity : " << extractor.porosity() << std::endl; std::cout << "Water volume fraction " << extractor.volume_fraction_water() << std::endl; //return EXIT_SUCCESS; // Obtain the boundary conditions AdimensionalSystemConstraints bc_constraints = get_bc_initial_constraints( the_database, specmicp_options.units_set ); AdimensionalSystemSolution bc_solution = solve_equilibrium( the_database, bc_constraints, specmicp_options ); // The constraints // -------------- // Boundary condition // 'list_fixed_nodes' lists the node with fixed composition std::vector list_fixed_nodes = {0}; // list_constraints lists the different speciation constraints in the system // Note : the total concentrations are computed from the initial solution, // and thus different total concentrations do not constitute a reason to create different constraints std::vector list_constraints = {cement_constraints, bc_constraints}; // index_constraints links a node to the set of constraints that will be used std::vector index_constraints(nb_nodes, 0); index_constraints[0] = 1; // Boundary conditions // This is the list of initial composition std::vector list_initial_composition = {cement_solution, bc_solution}; // This list links a node to its initial conditions std::vector index_initial_state(nb_nodes, 0); index_initial_state[0] = 1; // boundary condition // Variables // ----------- // Create the main set of variables // They will be initialized using the list of initial composition satdiff::SaturatedVariablesPtr variables = satdiff::init_variables(the_mesh, the_database, units_set, list_fixed_nodes, list_initial_composition, index_initial_state); // Staggers // --------- // This section initialize the staggers std::shared_ptr equilibrium_stagger = std::make_shared(list_constraints, index_constraints, specmicp_options); std::shared_ptr transport_stagger = std::make_shared(variables, list_fixed_nodes); set_transport_options(transport_stagger->options_solver()); UpscalingStaggerPtr upscaling_stagger = std::make_shared(the_database, units_set); // Solver // ------ // This section initialize the reactive transport solver ReactiveTransportSolver solver(transport_stagger, equilibrium_stagger, upscaling_stagger); set_reactive_solver_options(solver.get_options()); transport_stagger->initialize(variables); equilibrium_stagger->initialize(variables); upscaling_stagger->initialize(variables); // Some basic information about the simulation // First argument : the name of the simulation // Second argument : the output function will be called every 3600s SimulationInformation simul_info("carbo", 3600); simul_info.output_prefix = "out_carbo_"; // Runner // ------- // Create the runner : loop through the timestep ReactiveTransportRunner runner(solver, 0.1, 100.0, simul_info); // Create the output class OutputPolicy output_policy(simul_info, the_mesh, the_database, specmicp_options.units_set); // and bind it to the runner runner.set_output_policy(std::bind(&OutputPolicy::output, &output_policy, std::placeholders::_1, std::placeholders::_2)); // Solve the problem runner.run_until(30*24*3600, cast_var_to_base(variables)); // output information at the end of the timestep io::print_minerals_profile(the_database, variables, the_mesh, simul_info.complete_filepath("profiles_end", "dat")); io::print_components_total_aqueous_concentration(the_database, variables, the_mesh, specmicp_options.units_set, simul_info.complete_filepath("c_profiles_end", "dat")); io::print_components_total_solid_concentration(the_database, variables, the_mesh, specmicp_options.units_set, simul_info.complete_filepath("s_profiles_end", "dat")); } AdimensionalSystemSolverOptions get_specmicp_options() { AdimensionalSystemSolverOptions options; options.solver_options.maxiter_maxstep = 100; options.solver_options.maxstep = 50.0; options.solver_options.threshold_cycling_linesearch = 1e-6; options.solver_options.set_tolerance(1e-8, 1e-14); options.solver_options.disable_condition_check(); options.solver_options.disable_descent_direction(); options.solver_options.enable_non_monotone_linesearch(); options.solver_options.enable_scaling(); options.system_options.non_ideality_tolerance = 1e-14; options.system_options.cutoff_total_concentration = 1e-10; options.units_set.length = units::LengthUnit::centimeter; return options; } void set_transport_options(dfpmsolver::ParabolicDriverOptions& transport_options) { transport_options.maximum_iterations = 450; transport_options.quasi_newton = 3; transport_options.residuals_tolerance = 1e-8; transport_options.step_tolerance = 1e-14; transport_options.absolute_tolerance = 1e-18; transport_options.alpha = 1.0; //transport_options.linesearch = dfpmsolver::ParabolicLinesearch::Strang; transport_options.sparse_solver = SparseSolver::SparseLU; //transport_options.sparse_solver = SparseSolver::GMRES; transport_options.threshold_stationary_point = 1e-4; } void set_reactive_solver_options(reactmicp::solver::ReactiveTransportOptions& reactive_options) { reactive_options.maximum_iterations = 50; //500; reactive_options.residuals_tolerance = 1e-2; reactive_options.good_enough_tolerance = 1.0; reactive_options.absolute_residuals_tolerance = 1e-14; reactive_options.implicit_upscaling = true; } RawDatabasePtr get_database(const std::string& path_to_database) { database::Database the_database(path_to_database); std::map swapping({ {"H[+]","HO[-]"}, {"Si(OH)4", "SiO(OH)3[-]"}, {"Al[3+]","Al(OH)4[-]"} }); the_database.swap_components(swapping); the_database.remove_gas_phases(); return the_database.get_database(); } AdimensionalSystemConstraints get_cement_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set) { // Vector init_min_publi(5); // init_min_publi << 12.9, 1.62, 0.605, 0.131, 0.001; // Vector init_min; // init_min = initial_compo(init_min_publi); // std::cout << "Init min \n ---- \n" << init_min << "\n ---- \n" << std::endl; Vector oxyde_compo(4); oxyde_compo << 66.98, 21.66, 7.19, 2.96; Vector species_compo; compo_from_oxyde(oxyde_compo, species_compo); scalar_t mult = 1e-6; //scalar_t mult = 6.73153e-4; //scalar_t mult = 0.001296315; //init_min *= 6.71146e-4; //species_compo *= 0.947e-2; // poro 0.47 //species_compo *= 1.08e-2; // poro 0.4 //species_compo *= 1.25e-2; // poro 0.3 species_compo *= 1.518e-2; Formulation formulation; formulation.mass_solution = 1.0; formulation.amount_minerals = { {"C3S", species_compo(0)}, {"C2S", species_compo(1)}, {"C3A", species_compo(2)}, {"Gypsum", species_compo(3)}, {"Calcite", species_compo(0)*1e-3} // {"Portlandite", init_min(0)}, // {"CSH,jennite", init_min(1)}, // {"Monosulfoaluminate", init_min(2)}, // {"Ettringite", init_min(3)}, // {"Calcite", init_min(4)} }; formulation.extra_components_to_keep = {"HCO3[-]"}; formulation.concentration_aqueous = { {"Na[+]", mult*1.0298}, {"K[+]", mult*0.0801}, {"Cl[-]", mult*0.0001}, {"HO[-]", mult*1.8298} }, formulation.minerals_to_keep = { "Portlandite", "CSH,jennite", "CSH,tobermorite", "SiO2,am", "Calcite", "Al(OH)3,am", "C3AH6", "C4AH13", "C2AH8", "CAH10", "Monosulfoaluminate", "Tricarboaluminate", "Monocarboaluminate", "Hemicarboaluminate", "Straetlingite", "Gypsum", "Ettringite", "Thaumasite" }; Dissolver dissolver(the_database); dissolver.set_units(units_set); AdimensionalSystemConstraints constraints; constraints.set_charge_keeper(1); constraints.total_concentrations = dissolver.dissolve(formulation); std::cout << constraints.total_concentrations << std::endl; constraints.set_saturated_system(); return constraints; } AdimensionalSystemConstraints get_bc_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set) { const scalar_t rho_w = laws::density_water(units::celsius(25.0), units_set.length, units_set.mass); const scalar_t nacl = 0.3*rho_w; const scalar_t kcl = 0.28*rho_w; Vector total_concentrations; total_concentrations.setZero(the_database->nb_component()); total_concentrations(the_database->get_id_component("K[+]")) = kcl; total_concentrations(the_database->get_id_component("Cl[-]")) = nacl + kcl; total_concentrations(the_database->get_id_component("Na[+]")) = nacl; total_concentrations(the_database->get_id_component("SiO(OH)3[-]")) = 0.0001*rho_w; AdimensionalSystemConstraints constraints; constraints.add_fixed_activity_component(the_database->get_id_component("HO[-]"), -10.3); constraints.set_charge_keeper(the_database->get_id_component("HCO3[-]")); constraints.total_concentrations = total_concentrations; constraints.set_saturated_system(); constraints.disable_surface_model(); constraints.fixed_fugacity_cs ={}; return constraints; } AdimensionalSystemSolution get_bc_initial_compo( RawDatabasePtr the_database, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolverOptions& options ) { Vector variables; AdimensionalSystemSolver solver(the_database, constraints, options); micpsolver::MiCPPerformance perf = solver.solve(variables, true); if (perf.return_code <= micpsolver::MiCPSolverReturnCode::NotConvergedYet) throw std::runtime_error("Failed to solve initial composition"); std::cout << variables << std::endl; return solver.get_raw_solution(variables); } //AdimensionalSystemSolution get_cement_initial_compo( // RawDatabasePtr the_database, // const AdimensionalSystemConstraints& constraints, // const AdimensionalSystemSolverOptions& options // ) //{ // AdimensionalSystemSolver solver(the_database, // constraints, // options); // Vector variables; // solver.initialise_variables( // variables, // 0.4, // { // {"HO[-]", -1.2}, // {"Al(OH)4[-]", -4}, // {"HCO3[-]", -5}, // {"Ca[2+]", -1.6} // }); // micpsolver::MiCPPerformance perf = solver.solve(variables); // if (perf.return_code <= micpsolver::MiCPSolverReturnCode::NotConvergedYet) // throw std::runtime_error("Failed to solve initial composition"); // std::cout << variables << std::endl; // return solver.get_raw_solution(variables); //} void compo_from_oxyde(Vector& compo_oxyde, Vector& compo_species) { constexpr double M_CaO = 56.08; constexpr double M_SiO2 = 60.09; constexpr double M_Al2O3 = 101.96; constexpr double M_SO3 = 80.06; Eigen::MatrixXd compo_in_oxyde(4, 4); Vector molar_mass(4); molar_mass << 1.0/M_CaO, 1.0/M_SiO2, 1.0/M_Al2O3, 1.0/M_SO3; compo_oxyde = compo_oxyde.cwiseProduct(molar_mass); //C3S C2S C3A Gypsum compo_in_oxyde << 3, 2, 3, 1, // CaO 1, 1, 0, 0, // SiO2 0, 0, 1, 0, // Al2O3 0, 0, 0, 1; // SO3 Eigen::ColPivHouseholderQR solver(compo_in_oxyde); compo_species = solver.solve(compo_oxyde); } Vector initial_compo(const Vector& publi) { Matrix publi_stochio(5,5); publi_stochio << 1, 0, 0, 0, 0, 9, 6, 0, 0, 0, 3, 0, 1, 1, 0, 3, 0, 1, 3, 0, 0, 0, 0, 0, 1; Matrix cemdata_stochio(5, 5); cemdata_stochio << 1, 0, 0, 0, 0, 1.0/0.6, 1.0, 0, 0, 0, 3, 0, 1, 1, 0, 3, 0, 1, 3, 0, 0, 0, 0, 0, 1; Vector oxyde; Eigen::ColPivHouseholderQR solver(publi_stochio); oxyde = solver.solve(publi); Vector for_cemdata = cemdata_stochio*oxyde; return for_cemdata; } mesh::Mesh1DPtr get_mesh(scalar_t dx) { const scalar_t total_length = 0.75/2.0 + dx; //cm const scalar_t height = 20.0; index_t nb_nodes = total_length/dx + 1; return mesh::uniform_axisymmetric_mesh1d(nb_nodes, total_length, dx, height); } mesh::Mesh1DPtr get_mesh() { Vector radius(71); const scalar_t height = 20; // radius << // 3.751, // 3.750, // 3.749, // 3.748, // 3.747, // 3.745, // 3.740, // 3.735, // 3.730, // 3.720, // 3.710, // 3.700, // 3.675, // 3.650, // 3.625, // 3.600, // 3.575, // 3.550, // 3.525, // 3.500, // 3.475, // 3.450, // 3.425, // 3.400, // 3.375, // 3.350, // 3.325, // 3.300, // 3.250, // 3.200, // 3.150, // 3.100, // 3.050, // 3.000, // 2.975, // 2.950, // 2.925, // 2.900, // 2.875, // 2.850, // 2.825, // 2.800, // 2.775, // 2.750, // 2.700, // 2.650; radius << 3.751, 3.750, 3.745, 3.740, 3.735, 3.730, 3.720, 3.710, 3.700, 3.690, 3.680, 3.670, 3.660, 3.645, 3.630, 3.615, 3.600, 3.580, 3.560, 3.540, 3.520, 3.500, 3.475, 3.450, 3.425, 3.400, 3.375, 3.350, 3.325, 3.300, 3.275, 3.250, 3.225, 3.200, 3.175, 3.150, 3.125, 3.100, 3.050, 3.025, 3.000, 2.950, 2.900, 2.850, 2.800, 2.750, 2.700, 2.650, 2.600, 2.550, 2.500, 2.450, 2.400, 2.350, 2.300, 2.250, 2.200, 2.150, 2.100, 2.050, 2.000, 1.950, 1.900, 1.850, 1.800, 1.750, 1.700, 1.650, 1.600, 1.550, 1.500 ; radius = radius/10; return mesh::axisymmetric_mesh1d(radius, height); } diff --git a/examples/reactmicp/saturated_react/carbonationfe.cpp b/examples/reactmicp/saturated_react/carbonationfe.cpp index 9bd5c73..6229e12 100644 --- a/examples/reactmicp/saturated_react/carbonationfe.cpp +++ b/examples/reactmicp/saturated_react/carbonationfe.cpp @@ -1,791 +1,762 @@ -/*------------------------------------------------------- - -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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University 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 OWNER 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. - ----------------------------------------------------------*/ - // ============================================ // Saturated carbonation of a cement past // ============================================= // This file can be used to learn how to use ReactMiCP // Include ReactMiCP #include "reactmicp.hpp" // Physical laws #include "physics/laws.hpp" // A simple timer #include "utils/timer.hpp" #include #include #include // we use the following namespaces using namespace specmicp; using namespace reactmicp; using namespace reactmicp::systems; using namespace specmicp::reactmicp::systems::satdiff; using namespace reactmicp::solver; // We declare some functions that we will be using : // Database // ======== // Parse and Prepare the database RawDatabasePtr get_database(const std::string& path_to_database); // Boundary and initial conditions // =============================== // Return the chemistry constraints for the inital condition AdimensionalSystemConstraints get_cement_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set); // return the chemistry constraints for the boundary condition AdimensionalSystemConstraints get_bc_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set); void compo_oxyde_to_mole(Vector& compo_oxyde); // The mesh // ======== // There is two version // a uniform mesh mesh::Mesh1DPtr get_mesh(scalar_t dx); // and a non uniform mesh mesh::Mesh1DPtr get_mesh(); // Options // ======= // Speciation solver options AdimensionalSystemSolverOptions get_specmicp_options(); // Transport options void set_transport_options(dfpmsolver::ParabolicDriverOptions& transport_options); // Reactive Solver options void set_reactive_solver_options(reactmicp::solver::ReactiveTransportOptions& reactive_options); // Upscaling // ========= // Upscaling is the stagger in charge of finding the porosity and transport properties // This is a class that is dependant on the problem to solve and should be defined by the user // The following class is an example on how to define such a class // The Upscaling class should inherit from UpscalingStaggerBase class CarboUspcaling: public solver::UpscalingStaggerBase { public: // Initiation // This is not call automatically so can be adjusted by the user CarboUspcaling(RawDatabasePtr the_database, units::UnitsSet the_units): m_data(the_database), m_units_set(the_units), m_dt(HUGE_VAL) { } // Initialize the stagger at the beginning of the computation // The porosity and transport properties should be initialized here void initialize(VariablesBasePtr var) { SaturatedVariablesPtr true_var = cast_var_from_base(var); true_var->upscaling_variables().setZero(); for (index_t node=0; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); } } // Initialize the stagger at the beginning of a timestep // Typically do nothing but erase the "dot" variable (velocity such as the vel_porosity) void initialize_timestep(scalar_t dt, VariablesBasePtr var) { SaturatedVariablesPtr true_var = cast_var_from_base(var); m_dt = dt; for (index_t node=1; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); true_var->vel_porosity(node) = 0.0; } } //! This is the main function called during a timestep StaggerReturnCode restart_timestep(VariablesBasePtr var) { SaturatedVariablesPtr true_var = cast_var_from_base(var); for (index_t node=1; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); } return StaggerReturnCode::ResidualMinimized; // This is the value that should be returned if everything is ok } // A function that return the diffusion coefficient when porosity is equal to 'porosity' scalar_t coeff_diffusion_law(scalar_t porosity) { static constexpr scalar_t de_0 = 2.726e-12; //1e-11; static constexpr scalar_t factor = 1e4; static constexpr scalar_t porosity_r = 0.02; const scalar_t ratio = ((porosity - porosity_r)/(0.25 - porosity_r)); const scalar_t d_e = factor*de_0*std::pow(ratio, 3.32); return std::min(d_e, 1e4*1e-10); } // Compute the upscaling for 'node' void upscaling_one_node(index_t node, SaturatedVariablesPtr true_var) { // AdimensionalSystemSolutionExtractor is the class to use to // extract information from a SpecMiCP solution // To obtain correct information the correct units must be used AdimensionalSystemSolutionExtractor extractor(true_var->equilibrium_solution(node), m_data, m_units_set); // We can obtain the porosity very easily : scalar_t porosity = extractor.porosity(); true_var->vel_porosity(node) += (porosity - true_var->porosity(node))/m_dt; true_var->porosity(node) = porosity; true_var->diffusion_coefficient(node) = coeff_diffusion_law(porosity); } private: RawDatabasePtr m_data; units::UnitsSet m_units_set; index_t m_id_cshj; scalar_t m_initial_sat_cshj; scalar_t m_dt; }; // ============== // Output // ============== // Many information is generated throughout a computation and we can't save everything // The reactmicp runner can call a function to output the desired information // Here the output function is a member function for convenience class OutputPolicy { public: // Initialise the output // SimulationInformation contain basic information from the simulation OutputPolicy(const SimulationInformation& simul_info, mesh::Mesh1DPtr the_mesh, RawDatabasePtr the_database, units::UnitsSet the_units): m_mesh(the_mesh), m_database(the_database), m_units(the_units) { // Open the files // Save the pH out_c_ph.open(simul_info.complete_filepath("ph", suffix)); // Save the total aqueous concentration of HCO3[-] out_c_hco3.open(simul_info.complete_filepath("c_hco3", suffix)); // save the total solid concentration of s_ca out_s_ca.open(simul_info.complete_filepath("s_ca", suffix)); // Save the volume fraction of calcite out_calcite.open(simul_info.complete_filepath("calcite", suffix)); // Save the porosity out_poro.open(simul_info.complete_filepath("poro", suffix)); // save useful indices from the database m_id_hco3 = m_database->get_id_component("HCO3[-]"); m_id_ca = m_database->get_id_component("Ca[2+]"); m_id_calcite = m_database->get_id_mineral("Calcite"); } void output(scalar_t time, VariablesBasePtr variables) { SaturatedVariablesPtr true_var = cast_var_from_base(variables); out_c_ph << time; out_c_hco3 << time; out_s_ca << time; out_calcite << time; out_poro << time; for (index_t node: m_mesh->range_nodes()) { // Again AdimensionalSystemSolutionExtractor is used to obtain information about the speciation system AdimensionalSystemSolutionExtractor extractor(true_var ->equilibrium_solution(node), m_database, m_units); out_c_ph << "\t" << extractor.pH(); out_c_hco3 << "\t" << true_var->aqueous_concentration(node, m_id_hco3); out_s_ca << "\t" << true_var->solid_concentration(node, m_id_ca); out_calcite << "\t" << extractor.volume_fraction_mineral(m_id_calcite); out_poro << "\t" << extractor.porosity(); } out_c_hco3 << std::endl; out_c_ph << std::endl; out_s_ca << std::endl; out_calcite << std::endl; out_poro << std::endl; } private: mesh::Mesh1DPtr m_mesh; RawDatabasePtr m_database; units::UnitsSet m_units; std::string suffix { "dat" }; std::ofstream out_c_ph; std::ofstream out_c_hco3; std::ofstream out_s_ca; std::ofstream out_calcite; std::ofstream out_poro; index_t m_id_hco3; index_t m_id_ca; index_t m_id_calcite; }; // =================== // MAIN // =================== int main() { // initialize eigen // This is needed if OpenMP is used Eigen::initParallel(); // Setup the log // The output will be on cerr specmicp::logger::ErrFile::stream() = &std::cerr; // And only Warning and error messages will be printed specmicp::stdlog::ReportLevel() = specmicp::logger::Warning; // The database // ------------- // Obtain the database RawDatabasePtr the_database = get_database("../data/cemdata.js"); // SpecMiCP options // ---------------- // Set the options AdimensionalSystemSolverOptions specmicp_options = get_specmicp_options(); units::UnitsSet units_set = specmicp_options.units_set; // The mesh // -------- // Obtain the mesh mesh::Mesh1DPtr the_mesh = get_mesh(0.0050); // uniform //mesh::Mesh1DPtr the_mesh = get_mesh(); // non uniform index_t nb_nodes = the_mesh->nb_nodes(); // just boilerplate to make things easier // Print the mesh io::print_mesh("out_carbo_mesh.dat", the_mesh, units::LengthUnit::centimeter); // Initial and boundary conditions // -------------------------------- // Obtain the initial constraints // Note : the database is modified at this point // Only the relevant components are kept at this point AdimensionalSystemConstraints cement_constraints = get_cement_initial_constraints(the_database, units_set); // Obtain the initial condition AdimensionalSystemSolution cement_solution = solve_equilibrium( the_database, cement_constraints, specmicp_options); // Just to check that everything is ok ! AdimensionalSystemSolutionExtractor extractor(cement_solution, the_database, units_set); std::cout << "Porosity : " << extractor.porosity() << std::endl; std::cout << "Water volume fraction " << extractor.volume_fraction_water() << std::endl; //return EXIT_SUCCESS; // Obtain the boundary conditions AdimensionalSystemConstraints bc_constraints = get_bc_initial_constraints( the_database, specmicp_options.units_set ); AdimensionalSystemSolution bc_solution = solve_equilibrium( the_database, bc_constraints, specmicp_options ); // The constraints // -------------- // Boundary condition // 'list_fixed_nodes' lists the node with fixed composition std::vector list_fixed_nodes = {0}; // list_constraints lists the different speciation constraints in the system // Note : the total concentrations are computed from the initial solution, // and thus different total concentrations do not constitute a reason to create different constraints std::vector list_constraints = {cement_constraints, bc_constraints}; // index_constraints links a node to the set of constraints that will be used std::vector index_constraints(nb_nodes, 0); index_constraints[0] = 1; // Boundary conditions // This is the list of initial composition std::vector list_initial_composition = {cement_solution, bc_solution}; // This list links a node to its initial conditions std::vector index_initial_state(nb_nodes, 0); index_initial_state[0] = 1; // boundary condition // Variables // ----------- // Create the main set of variables // They will be initialized using the list of initial composition satdiff::SaturatedVariablesPtr variables = satdiff::init_variables(the_mesh, the_database, units_set, list_fixed_nodes, list_initial_composition, index_initial_state); // Staggers // --------- // This section initialize the staggers std::shared_ptr equilibrium_stagger = std::make_shared(list_constraints, index_constraints, specmicp_options); std::shared_ptr transport_stagger = std::make_shared(variables, list_fixed_nodes); set_transport_options(transport_stagger->options_solver()); UpscalingStaggerPtr upscaling_stagger = std::make_shared(the_database, units_set); // Solver // ------ // This section initialize the reactive transport solver ReactiveTransportSolver solver(transport_stagger, equilibrium_stagger, upscaling_stagger); set_reactive_solver_options(solver.get_options()); transport_stagger->initialize(variables); equilibrium_stagger->initialize(variables); upscaling_stagger->initialize(variables); // Some basic information about the simulation // First argument : the name of the simulation // Second argument : the output function will be called every 3600s SimulationInformation simul_info("carbo", 3600); simul_info.output_prefix = "out_carbo_"; // Runner // ------- // Create the runner : loop through the timestep ReactiveTransportRunner runner(solver, 0.1, 100.0, simul_info); // Create the output class OutputPolicy output_policy(simul_info, the_mesh, the_database, specmicp_options.units_set); // and bind it to the runner runner.set_output_policy(std::bind(&OutputPolicy::output, &output_policy, std::placeholders::_1, std::placeholders::_2)); // Solve the problem runner.run_until(30*24*3600, cast_var_to_base(variables)); // output information at the end of the timestep io::print_minerals_profile(the_database, variables, the_mesh, simul_info.complete_filepath("profiles_end", "dat")); io::print_components_total_aqueous_concentration(the_database, variables, the_mesh, specmicp_options.units_set, simul_info.complete_filepath("c_profiles_end", "dat")); io::print_components_total_solid_concentration(the_database, variables, the_mesh, specmicp_options.units_set, simul_info.complete_filepath("s_profiles_end", "dat")); } AdimensionalSystemSolverOptions get_specmicp_options() { AdimensionalSystemSolverOptions options; options.solver_options.maxiter_maxstep = 100; options.solver_options.maxstep = 50.0; options.solver_options.threshold_cycling_linesearch = 1e-6; options.solver_options.set_tolerance(1e-8, 1e-16); options.solver_options.disable_condition_check(); options.solver_options.disable_descent_direction(); options.solver_options.enable_non_monotone_linesearch(); options.solver_options.enable_scaling(); options.system_options.non_ideality_tolerance = 1e-14; options.system_options.cutoff_total_concentration = 1e-10; options.system_options.scaling_electron = 1e4; options.units_set.length = units::LengthUnit::centimeter; return options; } void set_transport_options(dfpmsolver::ParabolicDriverOptions& transport_options) { transport_options.maximum_iterations = 450; transport_options.quasi_newton = 3; transport_options.residuals_tolerance = 1e-8; transport_options.step_tolerance = 1e-14; transport_options.absolute_tolerance = 1e-18; transport_options.alpha = 1.0; //transport_options.linesearch = dfpmsolver::ParabolicLinesearch::Strang; transport_options.sparse_solver = SparseSolver::SparseLU; //transport_options.sparse_solver = SparseSolver::GMRES; transport_options.threshold_stationary_point = 1e-4; } void set_reactive_solver_options(reactmicp::solver::ReactiveTransportOptions& reactive_options) { reactive_options.maximum_iterations = 50; //500; reactive_options.residuals_tolerance = 1e-2; reactive_options.good_enough_tolerance = 1.0; reactive_options.absolute_residuals_tolerance = 1e-14; reactive_options.implicit_upscaling = true; } RawDatabasePtr get_database(const std::string& path_to_database) { database::Database the_database(path_to_database); std::map swapping({ {"H[+]","HO[-]"}, {"Si(OH)4", "SiO(OH)3[-]"}, {"Al[3+]","Al(OH)4[-]"}, {"Fe[2+]", "Fe(OH)4[-]"} }); the_database.swap_components(swapping); the_database.remove_gas_phases(); return the_database.get_database(); } AdimensionalSystemConstraints get_cement_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set) { Vector oxyde_compo(5); oxyde_compo << 66.98, 21.66, 2.78, 2.96, 4.41; compo_oxyde_to_mole(oxyde_compo); scalar_t mult = laws::density_water(units::celsius(25.0), units_set.length, units_set.mass); //oxyde_compo *= 0.01098; //= 1e-2; //poro 0.4 oxyde_compo *= 0.00967; //= 1e-2; //poro 0.47 Formulation formulation; formulation.mass_solution = 1.0; formulation.amount_minerals = { {"CaO(ox)", oxyde_compo(0)}, {"SiO2(ox)", oxyde_compo(1)}, {"Al2O3(ox)", oxyde_compo(2)}, {"SO3(ox)", oxyde_compo(3)}, {"Fe2O3(ox)", oxyde_compo(4)}, {"Calcite", oxyde_compo(0)*1e-4} }; formulation.extra_components_to_keep = {"HCO3[-]"}; formulation.concentration_aqueous = { {"Na[+]", mult*1.0298}, {"K[+]", mult*0.0801}, {"Cl[-]", mult*0.0001}, {"HO[-]", mult*1.8298} }, formulation.minerals_to_keep = { "Portlandite", "CSH,jennite", "CSH,tobermorite", "SiO2,am", "Calcite", "Al(OH)3,am", "C3AH6", "C4AH13", "C2AH8", "CAH10", "Monosulfoaluminate", "Tricarboaluminate", "Monocarboaluminate", "Hemicarboaluminate", //"Straetlingite", "Gypsum", "Ettringite", //"Thaumasite", "C3FH6", "C4FH13", "C2FH8", "Fe(OH)3(mic)", "Fe-Ettringite", "Fe-Monosulfate", "Fe-Monocarbonate", "Fe-Hemicarbonate", //"Fe-Straetlingite", }; Dissolver dissolver(the_database); dissolver.set_units(units_set); AdimensionalSystemConstraints constraints; constraints.set_charge_keeper(1); constraints.total_concentrations = dissolver.dissolve(formulation); std::cout << constraints.total_concentrations << std::endl; constraints.set_saturated_system(); return constraints; } AdimensionalSystemConstraints get_bc_initial_constraints( RawDatabasePtr the_database, const units::UnitsSet& units_set) { const scalar_t rho_w = laws::density_water(units::celsius(25.0), units_set.length, units_set.mass); const scalar_t nacl = 0.3*rho_w; const scalar_t kcl = 0.28*rho_w; Vector total_concentrations; total_concentrations.setZero(the_database->nb_component()); total_concentrations(the_database->get_id_component("K[+]")) = kcl; total_concentrations(the_database->get_id_component("Cl[-]")) = nacl + kcl; total_concentrations(the_database->get_id_component("Na[+]")) = nacl; total_concentrations(the_database->get_id_component("SiO(OH)3[-]")) = 0.0001*rho_w; AdimensionalSystemConstraints constraints; constraints.add_fixed_activity_component(the_database->get_id_component("HO[-]"), -10.3); constraints.set_charge_keeper(the_database->get_id_component("HCO3[-]")); constraints.total_concentrations = total_concentrations; constraints.set_saturated_system(); constraints.disable_surface_model(); constraints.fixed_fugacity_cs ={}; return constraints; } AdimensionalSystemSolution get_bc_initial_compo( RawDatabasePtr the_database, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolverOptions& options ) { Vector variables; AdimensionalSystemSolver solver(the_database, constraints, options); micpsolver::MiCPPerformance perf = solver.solve(variables, true); if (perf.return_code <= micpsolver::MiCPSolverReturnCode::NotConvergedYet) throw std::runtime_error("Failed to solve initial composition"); //std::cout << variables << std::endl; return solver.get_raw_solution(variables); } void compo_oxyde_to_mole(Vector& compo_oxyde) { constexpr double M_CaO = 56.08; constexpr double M_SiO2 = 60.09; constexpr double M_Al2O3 = 101.96; constexpr double M_SO3 = 80.06; constexpr double M_FE2O3 = 159.7; Vector molar_mass(5); molar_mass << 1.0/M_CaO, 1.0/M_SiO2, 1.0/M_Al2O3, 1.0/M_SO3, 1.0/M_FE2O3; compo_oxyde = compo_oxyde.cwiseProduct(molar_mass); } mesh::Mesh1DPtr get_mesh(scalar_t dx) { const scalar_t total_length = 0.75/2.0 + dx; //cm const scalar_t height = 20.0; index_t nb_nodes = total_length/dx + 1; return mesh::uniform_axisymmetric_mesh1d(nb_nodes, total_length, dx, height); } mesh::Mesh1DPtr get_mesh() { Vector radius(71); const scalar_t height = 20; // radius << // 3.751, // 3.750, // 3.749, // 3.748, // 3.747, // 3.745, // 3.740, // 3.735, // 3.730, // 3.720, // 3.710, // 3.700, // 3.675, // 3.650, // 3.625, // 3.600, // 3.575, // 3.550, // 3.525, // 3.500, // 3.475, // 3.450, // 3.425, // 3.400, // 3.375, // 3.350, // 3.325, // 3.300, // 3.250, // 3.200, // 3.150, // 3.100, // 3.050, // 3.000, // 2.975, // 2.950, // 2.925, // 2.900, // 2.875, // 2.850, // 2.825, // 2.800, // 2.775, // 2.750, // 2.700, // 2.650; radius << 3.751, 3.750, 3.745, 3.740, 3.735, 3.730, 3.720, 3.710, 3.700, 3.690, 3.680, 3.670, 3.660, 3.645, 3.630, 3.615, 3.600, 3.580, 3.560, 3.540, 3.520, 3.500, 3.475, 3.450, 3.425, 3.400, 3.375, 3.350, 3.325, 3.300, 3.275, 3.250, 3.225, 3.200, 3.175, 3.150, 3.125, 3.100, 3.050, 3.025, 3.000, 2.950, 2.900, 2.850, 2.800, 2.750, 2.700, 2.650, 2.600, 2.550, 2.500, 2.450, 2.400, 2.350, 2.300, 2.250, 2.200, 2.150, 2.100, 2.050, 2.000, 1.950, 1.900, 1.850, 1.800, 1.750, 1.700, 1.650, 1.600, 1.550, 1.500 ; radius = radius/10; return mesh::axisymmetric_mesh1d(radius, height); } diff --git a/examples/reactmicp/saturated_react/react_leaching.cpp b/examples/reactmicp/saturated_react/react_leaching.cpp index 6028fbf..b4efac7 100644 --- a/examples/reactmicp/saturated_react/react_leaching.cpp +++ b/examples/reactmicp/saturated_react/react_leaching.cpp @@ -1,745 +1,744 @@ - #include "specmicp/adimensional/adimensional_system_solver.hpp" #include "specmicp/adimensional/adimensional_system_solution.hpp" #include "specmicp/problem_solver/dissolver.hpp" #include "specmicp/problem_solver/formulation.hpp" #include "specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include "reactmicp/solver/staggers_base/upscaling_stagger_base.hpp" #include "reactmicp/solver/staggers_base/stagger_structs.hpp" #include "reactmicp/solver/reactive_transport_solver.hpp" #include "reactmicp/systems/saturated_react/variables.hpp" #include "reactmicp/systems/saturated_react/transport_stagger.hpp" #include "reactmicp/systems/saturated_react/equilibrium_stagger.hpp" #include "reactmicp/systems/saturated_react/init_variables.hpp" #include "dfpm/meshes/axisymmetric_uniform_mesh1d.hpp" #include "dfpm/meshes/axisymmetric_mesh1d.hpp" #include "database/database.hpp" #include "reactmicp/solver/timestepper.hpp" #include "utils/timer.hpp" #include "utils/log.hpp" #include #include #include #include "utils/io/reactive_transport.hpp" using namespace specmicp; // Initial conditions // ================== specmicp::RawDatabasePtr leaching_database() { specmicp::database::Database thedatabase("../data/cemdata_specmicp.js"); std::map swapping ({ {"H[+]","HO[-]"}, {"Si(OH)4", "SiO(OH)3[-]"}, {"Al[3+]","Al(OH)4[-]"} }); thedatabase.remove_gas_phases(); thedatabase.swap_components(swapping); return thedatabase.get_database(); } const double M_CaO = 56.08; const double M_SiO2 = 60.09; const double M_Al2O3 = 101.96; const double M_SO3 = 80.06; void compo_from_oxyde(Vector& compo_oxyde, Vector& compo_species) { Eigen::MatrixXd compo_in_oxyde(4, 4); Vector molar_mass(4); molar_mass << 1.0/M_CaO, 1.0/M_SiO2, 1.0/M_Al2O3, 1.0/M_SO3; compo_oxyde = compo_oxyde.cwiseProduct(molar_mass); //C3S C2S C3A Gypsum compo_in_oxyde << 3, 2, 3, 1, // CaO 1, 1, 0, 0, // SiO2 0, 0, 1, 0, // Al2O3 0, 0, 0, 1; // SO3 Eigen::FullPivLU solver(compo_in_oxyde); compo_species = solver.solve(compo_oxyde); } AdimensionalSystemSolution initial_leaching_pb( RawDatabasePtr raw_data, scalar_t mult, units::UnitsSet the_units) { Formulation formulation; Vector oxyde_compo(4); oxyde_compo << 62.9, 20.6, 5.8, 3.1; Vector species_compo; compo_from_oxyde(oxyde_compo, species_compo); std::cout << species_compo << std::endl; scalar_t m_c3s = mult*species_compo(0); //0.6; scalar_t m_c2s = mult*species_compo(1); //0.2; scalar_t m_c3a = mult*species_compo(2); //0.1; scalar_t m_gypsum = mult*species_compo(3); //0.1; scalar_t wc = 0.5; scalar_t m_water = wc*1.0e-3*( m_c3s*(3*56.08+60.08) + m_c2s*(2*56.06+60.08) + m_c3a*(3*56.08+101.96) + m_gypsum*(56.08+80.06+2*18.02) ); formulation.mass_solution = m_water; formulation.amount_minerals = { {"C3S", m_c3s}, {"C2S", m_c2s}, {"C3A", m_c3a}, {"Gypsum", m_gypsum} }; specmicp::Vector total_concentrations = specmicp::Dissolver(raw_data).dissolve(formulation); specmicp::AdimensionalSystemConstraints constraints(total_concentrations); constraints.charge_keeper = 1; constraints.set_saturated_system(); specmicp::AdimensionalSystemSolverOptions options; options.solver_options.maxstep = 100.0; options.solver_options.max_iter = 200; options.solver_options.maxiter_maxstep = 100; options.solver_options.projection_min_variable = 1e-9; options.solver_options.set_tolerance(1e-10, 1e-14); options.solver_options.disable_crashing(); options.solver_options.enable_scaling(); options.solver_options.disable_descent_direction(); options.solver_options.enable_non_monotone_linesearch(); options.system_options.non_ideality_tolerance = 1e-10; options.units_set = the_units; specmicp::Vector x; specmicp::AdimensionalSystemSolver solver(raw_data, constraints, options); solver.initialise_variables(x, 0.8, -3.0); specmicp::micpsolver::MiCPPerformance perf = solver.solve(x, false); std::cout << "Initial return code : " << (int) perf.return_code << std::endl; if ((int) perf.return_code <= (int) specmicp::micpsolver::MiCPSolverReturnCode::NotConvergedYet) { throw std::runtime_error("Initial solution has not converged"); } return solver.get_raw_solution(x); } AdimensionalSystemSolution initial_blank_leaching_pb( RawDatabasePtr raw_data, scalar_t mult, units::UnitsSet the_units) { Formulation formulation; Vector oxyde_compo(4); oxyde_compo << 62.9, 20.6, 5.8, 3.1; Vector species_compo; compo_from_oxyde(oxyde_compo, species_compo); std::cout << species_compo << std::endl; scalar_t m_c3s = 0.6; scalar_t m_c2s = 0.2; scalar_t m_c3a = 0.1; scalar_t m_gypsum = 0.1; scalar_t wc = 0.8; scalar_t m_water = wc*1.0e-3*( m_c3s*(3*56.08+60.08) + m_c2s*(2*56.06+60.08) + m_c3a*(3*56.08+101.96) + m_gypsum*(56.08+80.06+2*18.02) ); formulation.mass_solution = m_water; formulation.amount_minerals = { {"SiO2,am", mult}, }; // formulation.concentration_aqueous = { // {"Ca[2+]", 1e-7}, // {"Al(OH)4[-]", 1e-7}, // {"SO4[2-]", 1e-7} // }; formulation.extra_components_to_keep = {"Ca[2+]", "SO4[2-]", "Al(OH)4[-]"}; specmicp::Vector total_concentrations = specmicp::Dissolver(raw_data).dissolve(formulation); specmicp::AdimensionalSystemConstraints constraints(total_concentrations); constraints.charge_keeper = 1; constraints.set_saturated_system(); specmicp::AdimensionalSystemSolverOptions options; options.solver_options.maxstep = 10.0; options.solver_options.max_iter = 200; options.solver_options.maxiter_maxstep = 200; options.solver_options.use_crashing = false; options.solver_options.use_scaling = true; options.solver_options.factor_descent_condition = -1.0; options.solver_options.factor_gradient_search_direction = 100; options.solver_options.projection_min_variable = 1e-9; options.solver_options.fvectol = 1e-4; options.solver_options.steptol = 1e-14; options.solver_options.non_monotone_linesearch = true; options.system_options.non_ideality_tolerance = 1e-10; options.units_set = the_units; Vector x; AdimensionalSystemSolver solver(raw_data, constraints, options); solver.initialise_variables(x, 0.75, -4.0); micpsolver::MiCPPerformance perf = solver.solve(x, false); std::cout << "Initial return code : " << (int) perf.return_code << std::endl; if ((int) perf.return_code <= (int) specmicp::micpsolver::MiCPSolverReturnCode::NotConvergedYet) { throw std::runtime_error("Initial solution has not converged"); } AdimensionalSystemSolution solution = solver.get_raw_solution(x); AdimensionalSystemSolutionModificator extractor(solution, raw_data, the_units); extractor.remove_solids(); Vector totconc(raw_data->nb_component()); totconc(0) = extractor.density_water()*extractor.total_aqueous_concentration(0); for (index_t component: raw_data->range_aqueous_component()) { totconc(component) = 0.01*extractor.density_water()*extractor.total_aqueous_concentration(component); } constraints.total_concentrations = totconc; solver = AdimensionalSystemSolver(raw_data, constraints, options); perf = solver.solve(x, false); specmicp_assert((int) perf.return_code > (int) micpsolver::MiCPSolverReturnCode::NotConvergedYet); return solver.get_raw_solution(x); } // Upscaling // ========= using namespace specmicp::reactmicp; using namespace specmicp::reactmicp::solver; using namespace specmicp::reactmicp::systems::satdiff; class LeachingUspcaling: public solver::UpscalingStaggerBase { public: LeachingUspcaling(RawDatabasePtr the_database, units::UnitsSet the_units): m_data(the_database), m_units_set(the_units) { } //! \brief Initialize the stagger at the beginning of the computation void initialize(VariablesBasePtr var) { SaturatedVariablesPtr true_var = cast_var_from_base(var); database::Database db_handler(m_data); m_dt = 1; m_id_cshj = db_handler.mineral_label_to_id("CSH,j"); m_initial_sat_cshj = true_var->equilibrium_solution(1).main_variables(m_data->nb_component()+m_id_cshj); //m_initial_sat_cshj = 0.36; std::cout << m_initial_sat_cshj << std::endl; true_var->upscaling_variables().setZero(); for (index_t node=0; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); } } //! \brief Initialize the stagger at the beginning of an iteration void initialize_timestep(scalar_t dt, VariablesBasePtr var) { SaturatedVariablesPtr true_var = cast_var_from_base(var); m_dt = dt; for (index_t node=1; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); true_var->vel_porosity(node) = 0.0; } } //! \brief Solve the equation for the timestep StaggerReturnCode restart_timestep(VariablesBasePtr var) { SaturatedVariablesPtr true_var = cast_var_from_base(var); for (index_t node=1; nodenb_nodes(); ++node) { upscaling_one_node(node, true_var); } return StaggerReturnCode::ResidualMinimized; } scalar_t diffusion_coefficient(scalar_t porosity) { const scalar_t factor = 1e4; scalar_t poro = factor*std::exp(9.85*porosity-29.08); // const scalar_t de_0 = 2.76e-12; // const scalar_t porosity_r = 0.02; // const scalar_t exponent = 3.32; //if (porosity > 0.7) // return factor*4.0*1e-10; // else // { // const scalar_t ratio = ((porosity - porosity_r)/(0.25 - porosity_r)); // poro = factor*de_0*std::pow(ratio, exponent); // } return std::min(poro,factor*1e-10); } void upscaling_one_node(index_t node, SaturatedVariablesPtr true_var) { AdimensionalSystemSolutionExtractor extractor(true_var->equilibrium_solution(node), m_data, m_units_set); scalar_t porosity = extractor.porosity(); ;//- true_var->equilibrium_solution(node).main_variables(m_data->nb_component)/m_initial_sat_cshj*0.05; //std::cout << "porosity : " << porosity // << " - saturation water" << true_var->equilibrium_solution(node).main_variables(0) << std::endl; true_var->vel_porosity(node) += (porosity - true_var->porosity(node))/m_dt; true_var->porosity(node) = porosity; true_var->diffusion_coefficient(node) = diffusion_coefficient(porosity); } private: RawDatabasePtr m_data; units::UnitsSet m_units_set; index_t m_id_cshj; scalar_t m_initial_sat_cshj; scalar_t m_dt; }; // void set_specmicp_options(AdimensionalSystemSolverOptions& options) { options.solver_options.maxstep = 10.0; options.solver_options.max_iter = 100; options.solver_options.maxiter_maxstep = 100; options.solver_options.use_crashing = false; options.solver_options.use_scaling = true; options.solver_options.factor_descent_condition = -1; options.solver_options.factor_gradient_search_direction = 100; options.solver_options.projection_min_variable = 1e-16; options.solver_options.fvectol = 1e-10; options.solver_options.steptol = 1e-14; options.solver_options.non_monotone_linesearch = true; options.system_options.non_ideality_tolerance = 1e-12; options.system_options.non_ideality_max_iter = 100; options.solver_options.threshold_cycling_linesearch = 1e-5; } void set_transport_options(dfpmsolver::ParabolicDriverOptions& transport_options) { transport_options.maximum_iterations = 450; transport_options.quasi_newton = 3; transport_options.residuals_tolerance = 1e-6; transport_options.step_tolerance = 1e-14; transport_options.alpha = 1; transport_options.linesearch = dfpmsolver::ParabolicLinesearch::Strang; transport_options.sparse_solver = SparseSolver::SparseLU; //transport_options.sparse_solver = SparseSolver::GMRES; transport_options.threshold_stationary_point = 1e-2; transport_options.absolute_tolerance = 1e-16; } void set_reactive_solver_options(ReactiveTransportOptions& solver_options) { solver_options.maximum_iterations = 100; solver_options.residuals_tolerance = 1e-2; solver_options.good_enough_tolerance = 1.0; solver_options.absolute_residuals_tolerance = 1e-16; solver_options.implicit_upscaling = true; } mesh::Mesh1DPtr get_mesh(scalar_t dx, index_t nb_nodes, index_t additional_nodes) { scalar_t radius = 3.5; //cm scalar_t height = 8.0; //cm radius = radius + additional_nodes*dx; return mesh::uniform_axisymmetric_mesh1d(nb_nodes+additional_nodes, radius, dx, height); } mesh::Mesh1DPtr get_mesh() { Vector radius(66); const scalar_t height = 8.0; radius << 3.5005, 3.5000, 3.4995, 3.4990, 3.4980, 3.4970, 3.4960, 3.4950, 3.4925, 3.4900, 3.4875, 3.4850, 3.4825, 3.4800, 3.4775, 3.4750, 3.4725, 3.4700, 3.4675, 3.4650, 3.4625, 3.4600, 3.4575, 3.4550, 3.4525, 3.4500, 3.4475, 3.445, 3.4425, 3.440, 3.4375, 3.435, 3.4325, 3.430, 3.4275, 3.425, 3.4225, 3.420, 3.4175, 3.415, 3.4125, 3.410, 3.4075, 3.405, 3.4025, 3.400, 3.3975, 3.395, 3.3925, 3.390, 3.3875, 3.385, 3.3825, 3.38, 3.3775, 3.3750, 3.3725, 3.3700, 3.3675, 3.365, 3.3625, 3.36, 3.3575, 3.355, 3.325, 3.3 ; return mesh::axisymmetric_mesh1d(radius, height); } void output_mesh(mesh::Mesh1DPtr the_mesh) { std::ofstream output_mesh; output_mesh.open("out_leaching_mesh.dat"); output_mesh << "Node\tPosition" << std::endl; for (index_t node: the_mesh->range_nodes()) { output_mesh << node << "\t" << the_mesh->get_position(node) << std::endl; } output_mesh.close(); } void print_minerals_profile( RawDatabasePtr the_database, SaturatedVariablesPtr variables, mesh::Mesh1DPtr the_mesh, const std::string& filepath ) { std::ofstream ofile(filepath); ofile << "Radius"; for (index_t mineral: the_database->range_mineral()) { ofile << "\t" << the_database->get_label_mineral(mineral); } ofile << "\t" << "Porosity"; ofile << "\t" << "pH"; ofile << std::endl; for (index_t node: the_mesh->range_nodes()) { ofile << the_mesh->get_position(node); AdimensionalSystemSolutionExtractor extractor(variables->equilibrium_solution(node), the_database, units::UnitsSet()); for (index_t mineral: the_database->range_mineral()) { ofile << "\t" << extractor.volume_fraction_mineral(mineral); } ofile << "\t" << variables->porosity(node); ofile << "\t" << extractor.pH(); ofile << std::endl; } ofile.close(); } // Main // ==== int main() { Eigen::initParallel(); specmicp::logger::ErrFile::stream() = &std::cerr; specmicp::stdlog::ReportLevel() = specmicp::logger::Warning; RawDatabasePtr raw_data = leaching_database(); units::UnitsSet the_units; the_units.length = units::LengthUnit::centimeter; AdimensionalSystemSolution initial = initial_leaching_pb(raw_data, 0.015, the_units); AdimensionalSystemSolutionModificator extractor(initial, raw_data, the_units); index_t id_ca = raw_data->get_id_component("Ca[2+]"); index_t id_si = raw_data->get_id_component("SiO(OH)3[-]"); std::cout << extractor.total_solid_concentration(id_ca) << " - " << extractor.porosity() << std::endl; extractor.scale_total_concentration(id_ca, 0.0145); std::cout << extractor.total_solid_concentration(id_ca) << " - " << extractor.porosity() << std::endl; std::cout << initial.main_variables << std::endl; AdimensionalSystemSolution blank = initial_blank_leaching_pb(raw_data, 0.005, the_units); std::cout << blank.main_variables << std::endl; scalar_t dx = 0.0005; index_t nb_nodes = 150; index_t additional_nodes = 1; //mesh::Mesh1DPtr the_mesh = get_mesh(dx, nb_nodes, additional_nodes); mesh::Mesh1DPtr the_mesh = get_mesh(); nb_nodes = the_mesh->nb_nodes(); std::vector list_initial_composition = {initial, blank}; std::vector index_initial_state(nb_nodes, 0); for (int i=0; i< additional_nodes; ++i) index_initial_state[i] = 1; std::vector list_fixed_nodes = {0, }; systems::satdiff::SaturatedVariablesPtr variables = systems::satdiff::init_variables(the_mesh, raw_data, the_units, list_fixed_nodes, list_initial_composition, index_initial_state); specmicp::AdimensionalSystemConstraints constraints; constraints.charge_keeper = 1; constraints.set_saturated_system(); constraints.inert_volume_fraction = 0.0; AdimensionalSystemSolverOptions options; set_specmicp_options(options); options.units_set = the_units; ChemistryStaggerPtr equilibrium_stagger = std::make_shared(nb_nodes, constraints, options); std::shared_ptr transport_stagger = std::make_shared(variables, list_fixed_nodes); dfpmsolver::ParabolicDriverOptions& transport_options = transport_stagger->options_solver(); set_transport_options(transport_options); UpscalingStaggerPtr upscaling_stagger = std::make_shared(raw_data, the_units); ReactiveTransportSolver solver(transport_stagger, equilibrium_stagger, upscaling_stagger); transport_stagger->initialize(variables); equilibrium_stagger->initialize(variables); upscaling_stagger->initialize(variables); set_reactive_solver_options(solver.get_options()); std::ofstream output_iter("out_leaching_iter.dat"); std::ofstream output_c_ca, output_s_ca, output_s_si; std::ofstream output_poro; std::ofstream output_loss_ca; output_c_ca.open("out_c_ca.dat"); output_s_ca.open("out_s_ca.dat"); output_s_si.open("out_s_si.dat"); output_poro.open("out_poro.dat"); output_loss_ca.open("out_loss_ca.dat"); scalar_t initial_ca = 0; for (index_t node: the_mesh->range_nodes()) { initial_ca += variables->solid_concentration(node, id_ca, variables->displacement()) * the_mesh->get_volume_cell(node); } scalar_t dt=2.0; io::print_reactmicp_performance_long_header(&output_iter); Timestepper timestepper(1.0, 500.0, 25*24*3600, 2); int cnt =0; while (timestepper.get_total() < timestepper.get_total_target()) { Timer step_timer; step_timer.start(); reactmicp::solver::ReactiveTransportReturnCode retcode = solver.solve_timestep(dt, variables); step_timer.stop(); io::print_reactmicp_performance_long(&output_iter, cnt, timestepper.get_total() , solver.get_perfs()); dt = timestepper.next_timestep(dt, retcode, solver.get_perfs().nb_iterations); if (retcode <= reactmicp::solver::ReactiveTransportReturnCode::NotConvergedYet) { dt = 1.0; variables->reset_main_variables(); retcode = solver.solve_timestep(dt, variables); dt = timestepper.next_timestep(dt, retcode, solver.get_perfs().nb_iterations); io::print_reactmicp_performance_long(&output_iter, cnt, timestepper.get_total(), solver.get_perfs()); } // std::cout << "time : " << total/3600/24 << std::endl // << "Iter : " << solver.get_perfs().nb_iterations << std::endl // << "Residuals : " << solver.get_perfs().residuals << std::endl; if (cnt % 100 == 0) { scalar_t time = timestepper.get_total()/3600.0/24.0; scalar_t sqrt_time = std::sqrt(time); output_c_ca << time; output_s_ca << time; output_s_si << time; output_loss_ca << time << "\t" << sqrt_time; output_poro << time; scalar_t amount_ca = 0.0; for (index_t node: the_mesh->range_nodes()) { amount_ca += variables->solid_concentration(node, id_ca, variables->displacement()) * the_mesh->get_volume_cell(node); output_c_ca << "\t" << variables->aqueous_concentration(node, id_ca, variables->displacement()); output_s_ca << "\t" << variables->solid_concentration( node, id_ca, variables->displacement()); output_s_si << "\t" << variables->solid_concentration( node, id_si, variables->displacement()); output_poro << "\t" << variables->porosity(node); } output_poro << std::endl; output_loss_ca << "\t" << (initial_ca - amount_ca)/1.75929e-2 << std::endl; output_c_ca << std::endl; output_s_ca << std::endl; output_s_si << std::endl; } ++cnt; } print_minerals_profile(raw_data, variables, the_mesh, "out_leaching_minerals_profile_25d.dat"); timestepper.set_total_target(90*24*3600); while (timestepper.get_total() < timestepper.get_total_target()) { Timer step_timer; step_timer.start(); reactmicp::solver::ReactiveTransportReturnCode retcode = solver.solve_timestep(dt, variables); step_timer.stop(); io::print_reactmicp_performance_long(&output_iter, cnt, timestepper.get_total() , solver.get_perfs()); dt = timestepper.next_timestep(dt, retcode, solver.get_perfs().nb_iterations); if (retcode <= reactmicp::solver::ReactiveTransportReturnCode::NotConvergedYet) { dt = 1.0; variables->reset_main_variables(); retcode = solver.solve_timestep(dt, variables); dt = timestepper.next_timestep(dt, retcode, solver.get_perfs().nb_iterations); io::print_reactmicp_performance_long(&output_iter, cnt, timestepper.get_total(), solver.get_perfs()); } // std::cout << "time : " << total/3600/24 << std::endl // << "Iter : " << solver.get_perfs().nb_iterations << std::endl // << "Residuals : " << solver.get_perfs().residuals << std::endl; if (cnt % 100 == 0) { scalar_t time = timestepper.get_total()/3600.0/24.0; scalar_t sqrt_time = std::sqrt(time); output_c_ca << time; output_s_ca << time; output_s_si << time; output_loss_ca << time << "\t" << sqrt_time; output_poro << time; scalar_t amount_ca = 0.0; for (index_t node: the_mesh->range_nodes()) { amount_ca += variables->solid_concentration(node, id_ca, variables->displacement()) * the_mesh->get_volume_cell(node); output_c_ca << "\t" << variables->aqueous_concentration(node, id_ca, variables->displacement()); output_s_ca << "\t" << variables->solid_concentration( node, id_ca, variables->displacement()); output_s_si << "\t" << variables->solid_concentration( node, id_si, variables->displacement()); output_poro << "\t" << variables->porosity(node); } output_poro << std::endl; output_loss_ca << "\t" << (initial_ca - amount_ca)/1.75929e-2 << std::endl; output_c_ca << std::endl; output_s_ca << std::endl; output_s_si << std::endl; } ++cnt; } io::print_reactmicp_timer(&std::cout, solver.get_timer()); } diff --git a/src/common.hpp b/src/common.hpp index 2ffe30e..6a38858 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -1,127 +1,130 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_COMMON_HPP #define SPECMICP_COMMON_HPP #include #include "boost/range/irange.hpp" //! \file common.hpp //! \brief types and initialization //! //! This file is expected to be included by all other files. //! It defines the main types used throughout SpecMiCP // ========== // Index Type // ========== // First, we need to define the type of an index, before including Eigen namespace specmicp { #ifndef EIGEN_DEFAULT_DENSE_INDEX_TYPE using index_t = std::ptrdiff_t; //!< Type of an index in a vector #else using index_t = EIGEN_DEFAULT_DENSE_INDEX_TYPE; #endif using uindex_t = typename std::make_unsigned::type; //!< Unsigned version of the index } // now we can include Eigen #ifndef EIGEN_DEFAULT_DENSE_INDEX_TYPE #define EIGEN_DEFAULT_DENSE_INDEX_TYPE specmicp::index_t #endif #include // ============ // Matrix stuff // ============ namespace specmicp { using scalar_t = double; //!< Type of a scalar // linear algebra //! A dense vector using Vector = Eigen::Matrix; //! A dense matrix using Matrix = Eigen::Matrix; // Range // ===== //! \brief Range //! //! used to iterate over species/elements/nodes/... using range_t = boost::iterator_range>; // constants // ========= //! \brief Id of an equation that is not an equation constexpr index_t no_equation = -1; //! \brief Id of a non-existant species constexpr index_t no_species = -1; //! \brief Precision used to compute jacobian constexpr scalar_t eps_jacobian = 1e-8; } // namespace specmicp // macros // ------ // a lot of the eigen stuff may raise an error if in Debug mode #ifdef NDEBUG constexpr bool ndebug { false }; #else constexpr bool ndebug { true }; #endif #define NOEXCEPT noexcept(ndebug) // in case I nee to add other stuff // also, can be used to disable specmic_assert but keep the Eigen stuff #ifdef SPECMICP_NO_DEBUG #define specmicp_assert #else #define specmicp_assert(x) assert(x) #endif // SPECMICP_NO_DEBUG #endif // SPECMICP_COMMON_HPP diff --git a/src/database.hpp b/src/database.hpp index 1b0f991..2842dd8 100644 --- a/src/database.hpp +++ b/src/database.hpp @@ -1,42 +1,45 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_HPP #define SPECMICP_DATABASE_HPP #ifndef SPECMICP_DATABASE_DATACONTAINER_HPP #include "database/data_container.hpp" #endif namespace specmicp { using RawDatabasePtr = database::RawDatabasePtr; } #endif // SPECMICP_DATABASE_HPP diff --git a/src/database/aqueous_selector.cpp b/src/database/aqueous_selector.cpp index 2fc2d8e..90c14b1 100644 --- a/src/database/aqueous_selector.cpp +++ b/src/database/aqueous_selector.cpp @@ -1,61 +1,64 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "aqueous_selector.hpp" namespace specmicp { namespace database { //! \brief Remove some specific aqueous species void AqueousSelector::remove_aqueous(const std::vector& id_aqueous) { const index_t new_nb_aqueous = data->nb_aqueous() - id_aqueous.size(); index_t new_id = 0; for (index_t aqueous: data->range_aqueous()) { auto it = std::find(id_aqueous.cbegin(), id_aqueous.cend(), aqueous); if (it == id_aqueous.end()) // if we need to keep the species { if (*it == aqueous) { ++new_id; continue; // nothing to change } data->aqueous.move_erase(aqueous, new_id); ++new_id; } } specmicp_assert(new_id == new_nb_aqueous); data->aqueous.resize(new_nb_aqueous); data->aqueous.set_valid(); } } // end namespace database } // end namespace specmicp diff --git a/src/database/aqueous_selector.hpp b/src/database/aqueous_selector.hpp index a9745c9..6eea25a 100644 --- a/src/database/aqueous_selector.hpp +++ b/src/database/aqueous_selector.hpp @@ -1,58 +1,61 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_AQUEOUSSELECTOR_HPP #define SPECMICP_DATABASE_AQUEOUSSELECTOR_HPP //! \file mineral_selector.hpp select minerals in the database #include "module.hpp" namespace specmicp { namespace database { //! \brief Select equilibrum minerals in the database //! //! Keep only the solid phases that the user wants class AqueousSelector: public DatabaseModule { public: AqueousSelector(RawDatabasePtr thedata): DatabaseModule(thedata) {} //! \brief Remove some specific aqueous species void remove_aqueous(const std::vector& id_aqueous); }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_MINERALSELECTOR_HPP diff --git a/src/database/data_container.cpp b/src/database/data_container.cpp index 05e2fae..35171fe 100644 --- a/src/database/data_container.cpp +++ b/src/database/data_container.cpp @@ -1,123 +1,126 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "data_container.hpp" #include "errors.hpp" namespace specmicp { namespace database { const std::string water_label{"H2O"}; //!< The water label in the database const std::string electron_label{"E[-]"}; //!< The electron label in the database scalar_t DataContainer::molar_volume_mineral(index_t m, units::LengthUnit length_unit) const { const auto& molar_volume = minerals.molar_volume(m); if (molar_volume < 0) { throw db_noninitialized_value("molar volume", minerals.get_label(m)); } return scaling_molar_volume(length_unit)*molar_volume; } scalar_t DataContainer::scaling_molar_volume(units::LengthUnit length_unit) const { scalar_t scaling = 1.0; if (length_unit == units::LengthUnit::meter) scaling = 1e-6; else if (length_unit == units::LengthUnit::decimeter) scaling = 1e-3; return scaling; } //! \brief Return the molar volume (m^3/mol) of a mineral scalar_t DataContainer::molar_volume_mineral(index_t m) const { const auto& molar_volume = minerals.molar_volume(m); if (molar_volume < 0) { throw db_noninitialized_value("molar volume", minerals.get_label(m)); } return 1e-6*molar_volume; } //! \brief Return the molar volume (m^3/mol) of a mineral governed by kinetic scalar_t DataContainer::molar_volume_mineral_kinetic(index_t m) const { const auto& molar_volume = minerals_kinetic.molar_volume(m); if (molar_volume < 0) { throw db_noninitialized_value("molar volume", minerals_kinetic.get_label(m)); } return 1e-6*molar_volume; } //! Return the molar mass of 'component' in 'mass_unit'/mol scalar_t DataContainer::molar_mass_basis(index_t component, units::MassUnit mass_unit) const NOEXCEPT { scalar_t scaling = 1.0; if (mass_unit == units::MassUnit::kilogram) scaling=1e-3; return molar_mass_basis(component)*scaling; } //! \brief Return the molar mass (kg/mol) of a mineral scalar_t DataContainer::molar_mass_mineral(index_t mineral) const { return 1e-3*components.molar_mass_compounds(minerals.get_nu_row(mineral)); } //! \brief Return the molar mass (kg/mol) of a mineral governed by kinetic scalar_t DataContainer::molar_mass_mineral_kinetic(index_t mineral) const { return 1e-3*components.molar_mass_compounds(minerals_kinetic.get_nu_row(mineral)); } //! Return the molar mass of 'mineral' in 'mass_unit'/mol scalar_t DataContainer::molar_mass_mineral(index_t mineral, units::MassUnit mass_unit) const { scalar_t scaling = 1.0; if (mass_unit == units::MassUnit::kilogram) scaling=1e-3; return scaling*components.molar_mass_compounds(minerals.get_nu_row(mineral)); } //! Return the molar mass of 'mineral_kinetic' in 'mass_unit'/mol scalar_t DataContainer::molar_mass_mineral_kinetic(index_t mineral_kinetic, units::MassUnit mass_unit) const { scalar_t scaling = 1.0; if (mass_unit == units::MassUnit::kilogram) scaling=1e-3; return scaling*components.molar_mass_compounds(minerals_kinetic.get_nu_row(mineral_kinetic)); } bool DataContainer::is_valid() { return (components.is_valid() and aqueous.is_valid() and minerals.is_valid() and minerals_kinetic.is_valid() and gas.is_valid() and sorbed.is_valid() ); } } // end namespace database } // end namespace specmicp diff --git a/src/database/data_container.hpp b/src/database/data_container.hpp index 86a8d83..7f2a379 100644 --- a/src/database/data_container.hpp +++ b/src/database/data_container.hpp @@ -1,326 +1,329 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_DATACONTAINER_HPP #define SPECMICP_DATABASE_DATACONTAINER_HPP //! \file data_container.hpp //! \brief Storage class for the thermodynamics database //! //! This class is supposed to be share by every thing else in specmicp #include "common.hpp" #include "physics/units.hpp" #include "species/component_list.hpp" #include "species/aqueous_list.hpp" #include "species/mineral_list.hpp" #include "species/gas_list.hpp" #include "species/sorbed_list.hpp" namespace specmicp { namespace database { extern const std::string water_label; //!< The water label in the database constexpr index_t water_id{0}; //!< Index of water in the database extern const std::string electron_label; //!< The electron label in the database constexpr index_t electron_id{1}; //!< Index of the electron in the database //! \brief Storage class - Contains the database //! //! - Should not be accessed directly but through interfaces //! Correct interfaces are subclasses of DatabaseModule //! - Should be shared with a smart pointer struct DataContainer { //! \name Basis //! \brief The basis contains the components // ========================================== //! @{ ComponentList components; //!< The basis //! \brief Return the number of components in the basis index_t nb_component() const {return components.size();} //! \brief Return the number of all aqueous components, not including water and electron index_t nb_aqueous_components() const noexcept {return nb_component()-2;} //! \brief Return the id of component 'label' //! //! Return no_species if the component does not exist index_t get_id_component(const std::string& label) const { return components.get_id(label); } //! \brief Return the id of component 'label' std::string get_label_component(index_t id) const{ return components.get_label(id); } //! \brief Return the molar mass of 'component' in g/mol scalar_t molar_mass_basis(index_t component) const NOEXCEPT {return components.molar_mass(component);} //! \brief Return the molar mass of 'component' in kg/mol scalar_t molar_mass_basis_si(index_t component) const NOEXCEPT {return 1e-3*molar_mass_basis(component);} //! \brief Return the molar mass of 'component' in 'mass_unit'/mol scalar_t molar_mass_basis(index_t component, units::MassUnit mass_unit) const NOEXCEPT; //! \brief Return the charge of a component const scalar_t& charge_component(index_t i) const NOEXCEPT {return components.charge(i);} //! \brief Return the 'a_i' Debye-Huckel parameter for a component const scalar_t& a_debye_component(index_t i) const NOEXCEPT {return components.a_debye(i);} //! \brief Return the 'b_i' extended Debye-Huckel parameter for a component const scalar_t& b_debye_component(index_t i) const NOEXCEPT {return components.b_debye(i);} //! \brief Return the index of the water in the basis constexpr static index_t water_index() noexcept { return water_id; } //! \brief return the index of the electron in the basis constexpr static index_t electron_index() noexcept { return electron_id; } //! \brief Range over the components range_t range_component() const { return components.range();} //! \brief Range over the aqueous components range_t range_aqueous_component() const { return boost::irange(static_cast(2), nb_component());} //! @} //! \name Secondary aqueous species //! \brief The secondary aqueous species // ========================================= //! @{ AqueousList aqueous; //!< The list of aqueous species //! \brief Return the number of aqueous species in the system (not counting components) index_t nb_aqueous() const {return aqueous.size();} //! \brief Return the stoichiometric coefficient of 'i' in the dissociation reaction of species 'j' const scalar_t& nu_aqueous(index_t j, index_t i) const {return aqueous.nu_ji(j, i);} //! \brief Return the logk of dissociation reaction of species 'j' const scalar_t& logk_aqueous(index_t j) const {return aqueous.logk(j);} //! \brief Return the id of aqueous species 'label' //! //! Return no_species if the aqueous species does not exist index_t get_id_aqueous(const std::string& label) const{ return aqueous.get_id(label); } //! \brief Return the id of aqueous species 'label' std::string get_label_aqueous(index_t id) const { return aqueous.get_label(id); } //! \brief Return the charge of a secondary aqueous species const scalar_t& charge_aqueous(index_t j) const NOEXCEPT {return aqueous.charge(j);} //! \brief Return the 'a_i' Debye-Huckel parameter for a secondary aqueous species const scalar_t& a_debye_aqueous(index_t j) const NOEXCEPT {return aqueous.a_debye(j);} //! \brief Return the 'b_i' extended Debye-Huckel parameter for a secondary aqueous species const scalar_t& b_debye_aqueous(index_t j) const NOEXCEPT {return aqueous.b_debye(j);} //! \brief Return true if the corresponding equation is a half-cell reaction bool is_half_cell_reaction(index_t aqueous_species) const NOEXCEPT { return (nu_aqueous(aqueous_species, electron_index()) != 0.0); } //! \brief Range over the secondary aqueous species range_t range_aqueous() const { return aqueous.range();} //! @} //! \name Sorbed species //! \brief The adsorbed species // ========================================= //! @{ SorbedList sorbed; //!< The list of sorbed species //! \brief Return the number of sorbed species index_t nb_sorbed() const {return sorbed.size();} //! \brief Return the stoichiometric coefficient of 'i' in the dissociation reaction of species 'j' const scalar_t& nu_sorbed(index_t j, index_t i) const {return sorbed.nu_ji(j, i);} //! \brief Return the logk of dissociation reaction of species 'j' const scalar_t& logk_sorbed(index_t j) const {return sorbed.logk(j);} //! \brief Return the number of sorption sites occupied by a sorbed species const scalar_t& nb_sorption_sites(index_t sorbed_species) const { return sorbed.nb_sorption_site_occupied(sorbed_species); } //! \brief Return the id of sorbed species 'label' //! //! Return no_species if the sorbed species does not exist index_t get_id_sorbed(const std::string& label) const { return sorbed.get_id(label); } //! \brief Return the id of sorbed species 'label' std::string get_label_sorbed(index_t id) const { return sorbed.get_label(id); } //! \brief Range over the sorbed species range_t range_sorbed() const { return boost::irange((index_t) 0, nb_sorbed());} //! \brief Return true if the corresponding equation is a half-cell reaction bool is_sorbed_half_cell_reaction(index_t sorbed_species) const { return (nu_sorbed(sorbed_species, electron_index()) != 0.0); } //! @} //! \name Minerals //! \brief The solid phases // ========================================= //! @{ MineralList minerals; //!< The list of solid phases at equilibrium MineralList minerals_kinetic; //!< The list of solid phases governed by kinetic laws //! \brief Returns the number of solid phases at equilibrium index_t nb_mineral() {return minerals.size();} //! \brief Returns the number of solid phases governed by kinetic laws index_t nb_mineral_kinetic() {return minerals_kinetic.size();} //! \brief Return the stoichiometric coefficient for 'component' in the dissolution reaction of 'mineral' const scalar_t& nu_mineral(index_t mineral, index_t component) const { return minerals.nu_ji(mineral, component); } //! \brief Return the stoichiometric coefficient for 'component' in the dissolution reaction of 'mineral' const scalar_t& nu_mineral_kinetic(index_t mineral, index_t component) const { return minerals_kinetic.nu_ji(mineral, component); } //! \brief Return the logk for the dissolution reaction of 'mineral' const scalar_t& logk_mineral(index_t mineral) const { return minerals.logk(mineral); } //! \brief Return the logk for dissolution reaction of 'mineral' const scalar_t& logk_mineral_kinetic(index_t mineral) const { return minerals_kinetic.logk(mineral); } //! \brief Return true if the corresponding equation is a half-cell reaction bool is_mineral_half_cell_reaction(index_t mineral_species) const { return (nu_mineral(mineral_species, electron_index()) != 0.0); } //! \brief Return true if the corresponding equation is a half-cell reaction bool is_mineral_kinetic_half_cell_reaction(index_t mineral_species) const { return (nu_mineral_kinetic(mineral_species, electron_index()) != 0.0); } //! \brief Return the id of solid phase 'label' //! //! Return no_species if the solid phase does not exist index_t get_id_mineral(const std::string& label) const { return minerals.get_id(label); } //! \brief Return the id of solid phase 'label' std::string get_label_mineral(index_t id) const { return minerals.get_label(id); } //! \brief Return the id of solid phase 'label' //! //! Return no_species if the solid phase does not exist index_t get_id_mineral_kinetic(const std::string& label) const { return minerals_kinetic.get_id(label); } //! \brief Return the id of solid phase 'label' std::string get_label_mineral_kinetic(index_t id) const { return minerals_kinetic.get_label(id); } //! \brief Range over the solid phases (at equilibrium) range_t range_mineral() const { return minerals.range();} //! \brief Range over the solid phases governed by equilibrium range_t range_mineral_kinetic() const { return minerals_kinetic.range();} //! \brief Return the molar mass (kg/mol) of a mineral scalar_t molar_mass_mineral(index_t mineral) const; //! \brief Return the molar mass (kg/mol) of a mineral governed by kinetic scalar_t molar_mass_mineral_kinetic(index_t mineral) const; //! \brief Return the molar mass of 'mineral' in 'mass_uinit'/mol scalar_t molar_mass_mineral(index_t mineral, units::MassUnit mass_unit) const; //! \brief Return the molar mass of 'mineral_kinetic' in 'mass_uinit'/mol scalar_t molar_mass_mineral_kinetic(index_t mineral_kinetic, units::MassUnit mass_unit) const; //! \brief Return the scaling factor for the molar volume scalar_t scaling_molar_volume(units::LengthUnit length_unit) const; //! \brief Return the molar volume whatever it is scalar_t unsafe_molar_volume_mineral(index_t m) const { return minerals.molar_volume(m); } //! \brief Return the molar volume (m^3/mol) of a mineral scalar_t molar_volume_mineral(index_t m) const; //! \brief Return the molar volume (m^3/mol) of a mineral governed by kinetic scalar_t molar_volume_mineral_kinetic(index_t m) const; //! \brief Return the molar volume of a mineral in mol/(length_unit)^3 scalar_t molar_volume_mineral(index_t m, units::LengthUnit length_unit) const; //! @} //! \name Gas //! \brief The gas present in the system // ========================================= //! @{ GasList gas; //!< The list of gas //! \brief Return the number of gas in the system index_t nb_gas() const {return gas.size();} //! \brief Return the stoichiometric coefficient of 'component' in the dissolution reaction of 'gas_id' const scalar_t& nu_gas(index_t gas_id, index_t component) const {return gas.nu_ji(gas_id, component);} //! \brief Return the logk of he dissolution reaction of 'gas_id' const scalar_t& logk_gas(index_t gas_id) const {return gas.logk(gas_id);} //! \brief Return true if the corresponding equation is a half-cell reaction bool is_gas_half_cell_reaction(index_t gas_species) const { return (nu_gas(gas_species, electron_index()) != 0.0); } //! \brief Return the id of gas 'label' //! //! Return no_species if the gas does not exist index_t get_id_gas(const std::string& label) const { return gas.get_id(label); } //! \brief Return the id of solid phase 'label' std::string get_label_gas(index_t id) const { return gas.get_label(id); } //! \brief Range over the gas phases range_t range_gas() const { return boost::irange((index_t) 0, nb_gas());} //! @} // Status // ------ //! Return true if the database is valid; bool is_valid(); }; } // end namespace database } // end namespace specmicp #include namespace specmicp { namespace database { //! \brief Pointer to a database //! //! This is a smart pointer so we don't have to worry about memory leaks. //! It is intented to be shared between all the modules that needs it. using RawDatabasePtr = std::shared_ptr; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_DATACONTAINER_HPP diff --git a/src/database/database.cpp b/src/database/database.cpp index 94cc6fa..52e1852 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -1,112 +1,115 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "database.hpp" #include "selector.hpp" #include "switch_basis.hpp" #include "mineral_selector.hpp" #include "reader.hpp" #include "oxydo_selector.hpp" namespace specmicp { namespace database { // this is a proxy to a DatabaseSelector void Database::remove_components(const std::vector& id_components_to_remove) { DatabaseSelector selector(data); selector.remove_component(id_components_to_remove); } // this is a proxy to a DatabaseSelector void Database::keep_only_components(const std::vector& id_components_to_keep) { DatabaseSelector selector(data); selector.keep_only_component(id_components_to_keep); } void Database::minerals_keep_only(const std::vector& minerals_to_keep) { MineralSelector(data).keep_only(minerals_to_keep); } void Database::minerals_keep_only(const std::vector& minerals_to_keep) { MineralSelector(data).keep_only(minerals_to_keep); } void Database::swap_components(std::map& swap_to_make) { BasisSwitcher(data).swap_components(swap_to_make); } void Database::parse_database(std::string filepath) { DataReader reader(filepath); set_database(reader.get_database()); } void Database::keep_only_components(const std::vector& labels_components_to_keep) { std::vector id_components_to_keep; id_components_to_keep.reserve(labels_components_to_keep.size()); for (auto it: labels_components_to_keep) { id_components_to_keep.push_back(safe_component_label_to_id(it)); } keep_only_components(id_components_to_keep); } void Database::remove_gas_phases() { DatabaseSelector(data).remove_all_gas(); } void Database::remove_solid_phases() { MineralSelector(data).remove_all_minerals(); } //! \brief Remove the half-cells reactions for components in 'list_components' void Database::remove_half_cell_reactions(const std::vector& list_components) { OxydoSelector(data).remove_half_cells(list_components); } //! \brief Remove the half-cells reactions for components in 'list_id_components' void Database::remove_half_cell_reactions(const std::vector& list_id_components) { OxydoSelector(data).remove_half_cells(list_id_components); } } // end namespace database } // end namespace specmicp diff --git a/src/database/database.hpp b/src/database/database.hpp index 990920c..bb50866 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -1,120 +1,123 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_DATABASE_HPP #define SPECMICP_DATABASE_DATABASE_HPP //! \file database.hpp Database management #include "module.hpp" #include namespace specmicp { //! \namespace database Database management namespace database { //! \brief Database management //! //! Prepare the database for the computation. //! This class is a proxy for one-tasked modules. class Database: public DatabaseModule { public: //! \brief Default constructor //! //! the method parse_database must be called to parse the json database Database() {} //! \brief Initialise the database py parsing 'filepath' Database(std::string filepath) { parse_database(filepath); } //! \brief initialise the database with the raw database Database(std::shared_ptr raw_data): DatabaseModule(raw_data) {} //! \brief Parse the database 'filepath' void parse_database(std::string filepath); //! \brief Return the database //! //! Return a smart pointer of a DataCotnainer instance //! Note : this is a read write access, be careful std::shared_ptr get_database() {return data;} //! \brief Change the basis //! //! @param new_basis list of id of the new basis //! //! The new basis is a list of id, id = id_component for no swapping //! or id = id_aqueous + nb_component for swapping a secondary species void switch_basis(std::vector& new_basis); //! \brief Swap some component in the basis void swap_components(std::map& swap_to_make); //! \brief Remove components not present in the system void remove_components(const std::vector& id_components_to_remove); //! \brief Keep only components in the id_components to keep void keep_only_components(const std::vector& id_components_to_keep); //! \brief Keep only components in the id_components to keep void keep_only_components(const std::vector& labels_components_to_keep); //! \brief Keep only some minerals at equilibrium //! //! The effect is to flag all the other minerals as "kinetic" void minerals_keep_only(const std::vector& minerals_to_keep); //! \brief Keep only some minerals at equilibrium //! //! The effect is to flag all the other minerals as "kinetic" void minerals_keep_only(const std::vector& minerals_to_keep); //! \brief Remove all gas species void remove_gas_phases(); //! \brief Remove all solid phases void remove_solid_phases(); //! \brief Remove the half-cells reactions for components in 'list_components' void remove_half_cell_reactions(const std::vector& list_components); //! \brief Remove the half-cells reactions for components in 'list_id_components' void remove_half_cell_reactions(const std::vector& list_id_components); }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_DATABASE_HPP diff --git a/src/database/errors.hpp b/src/database/errors.hpp index 81edef1..e7d5c29 100644 --- a/src/database/errors.hpp +++ b/src/database/errors.hpp @@ -1,96 +1,99 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_ERRORS_HPP #define SPECMICP_DATABASE_ERRORS_HPP #include #include #include #include "common.hpp" //! \file errors.hpp database errors definitions namespace specmicp { namespace database { // Error used when parsing and handling the database // ------------------------------------------------- //! \brief This error is thrown when a label does not exist class db_invalid_label: public std::invalid_argument { public: db_invalid_label(const std::string &msg): std::invalid_argument("Unknown label : " + msg) {} }; //! \brief This error is thrown when a bad syntax is detected in the database class db_invalid_syntax : public std::invalid_argument { public: db_invalid_syntax (const std::string &msg): std::invalid_argument("Invalid syntax : " + msg) {} }; //! \brief This error is thrown when a bad syntax is detected in the database class db_invalid_data : public std::invalid_argument { public: db_invalid_data (const std::string &msg): std::invalid_argument("Invalid syntax : " + msg) {} }; //! \brief This error is thrown when the database is not as expected class invalid_database : public std::invalid_argument { public: invalid_database (const std::string &msg): std::invalid_argument("Invalid Database : " + msg) {} }; //! \brief This error is thrown when a non initialised value is wanted class db_noninitialized_value : public std::runtime_error { public: db_noninitialized_value (const std::string &value, const std::string &species): std::runtime_error("Value was not initialized : " + value +", for species : "+species+".") {} }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_ERRORS_HPP diff --git a/src/database/mineral_selector.cpp b/src/database/mineral_selector.cpp index 12b407b..5a19951 100644 --- a/src/database/mineral_selector.cpp +++ b/src/database/mineral_selector.cpp @@ -1,93 +1,96 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "mineral_selector.hpp" namespace specmicp { namespace database { void MineralSelector::keep_only(const std::vector& minerals_to_keep) { // First we compute the new sizes const uindex_t nb_to_keep = minerals_to_keep.size(); const uindex_t nb_to_remove = data->nb_mineral() - nb_to_keep; const uindex_t nb_new_min_kin = data->nb_mineral_kinetic() + nb_to_remove; uindex_t new_id = 0; uindex_t new_id_kin = data->nb_mineral_kinetic(); // Then we assure that there is place for moving data data->minerals_kinetic.resize(nb_new_min_kin); // Then we move data for (index_t id: data->range_mineral()) { auto search = std::find(minerals_to_keep.begin(), minerals_to_keep.end(), id); if (search == minerals_to_keep.end() ) // to move to kinetic { data->minerals.move_erase_to(id, data->minerals_kinetic, new_id_kin); ++new_id_kin; } else { data->minerals.move_erase(id, new_id); ++new_id; } } specmicp_assert(new_id == nb_to_keep); // simple test to assure that everything is ok specmicp_assert(new_id_kin == nb_new_min_kin); // Finally we shrink the containers for the mineral at equilibrium data->minerals.resize(nb_to_keep); data->minerals.set_valid(); data->minerals_kinetic.set_valid(); } void MineralSelector::keep_only(const std::vector& minerals_to_keep) { std::vector ids(minerals_to_keep.size()); for (uindex_t min=0; minminerals = MineralList(0, data->nb_component()); data->minerals_kinetic = MineralList(0, data->nb_component()); data->minerals.set_valid(); data->minerals_kinetic.set_valid(); } } // end namespace database } // end namespace specmicp diff --git a/src/database/mineral_selector.hpp b/src/database/mineral_selector.hpp index 7a7f21e..84d47c6 100644 --- a/src/database/mineral_selector.hpp +++ b/src/database/mineral_selector.hpp @@ -1,65 +1,68 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_MINERALSELECTOR_HPP #define SPECMICP_DATABASE_MINERALSELECTOR_HPP //! \file mineral_selector.hpp select minerals in the database #include "module.hpp" namespace specmicp { namespace database { //! \brief Select equilibrum minerals in the database //! //! Keep only the solid phases that the user wants class MineralSelector: public DatabaseModule { public: MineralSelector(RawDatabasePtr thedata): DatabaseModule(thedata) {} //! \brief Keep only minerals with id in "minerals to keep" void keep_only(const std::vector& minerals_to_keep); //! \brief Keep only minerals in "minerals_to_keep" void keep_only(const std::vector& minerals_to_keep); //! \brief Remove all minerals from the databse void remove_all_minerals(); }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_MINERALSELECTOR_HPP diff --git a/src/database/module.hpp b/src/database/module.hpp index 22c9434..b985625 100644 --- a/src/database/module.hpp +++ b/src/database/module.hpp @@ -1,165 +1,168 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATAABASE_MODULE_HPP #define SPECMICP_DATAABASE_MODULE_HPP //! \file module.hpp base class for a database module #include "data_container.hpp" #include "errors.hpp" namespace specmicp { namespace database { //! \brief Base class for a database module class DatabaseModule { public: //! \brief Create a blank database DatabaseModule() { reset_database(); } //! \brief Use the raw database thedata DatabaseModule(RawDatabasePtr& thedata): data(thedata) {} //! \brief set the database void set_database(RawDatabasePtr& thedata) {data = thedata;} //! \brief set the database void set_database(RawDatabasePtr&& thedata) {data = thedata;} //! \brief (Re)set the database - create a blank database void reset_database() {data = std::make_shared();} //! \brief Return true if the database is valid bool is_valid() {return data->is_valid();} //! \brief Return the id of the mineral "label" //! //! Return no_species if label is not a mineral (at equilibrium) index_t mineral_label_to_id(const std::string& label) { return data->minerals.get_id(label); } //! \brief Safe version of mineral_label_to_id //! throw an error if the compounds cannot be found index_t safe_mineral_label_to_id(const std::string& label) { auto id = mineral_label_to_id(label); if (id == no_species) { throw db_invalid_label(label+" is not a mineral at equilibrium !"); } return id; } //! \brief Return the id of the mineral "label" //! //! Return no_species if label is not a mineral (at equilibrium) index_t mineral_kinetic_label_to_id(const std::string& label) { return data->minerals_kinetic.get_id(label); } //! \brief Safe version of mineral_kinetic_label_to_id //! throw an error if the compounds cannot be found index_t safe_mineral_kinetic_label_to_id(const std::string& label) { auto id = mineral_kinetic_label_to_id(label); if (id == no_species) { throw db_invalid_label(label+" is not a mineral governed by kinetics !"); } return id; } //! \brief Return the id of the component "label" //! //! Return no_species if "label" is not a component index_t component_label_to_id(const std::string& label) { return data->components.get_id(label); } //! \brief Safe version of 'component_label_to_id //! throw an error if the compounds cannot be found index_t safe_component_label_to_id(const std::string& label) { auto id = component_label_to_id(label); if (id == no_species) { throw db_invalid_label(label+" is not in the basis !"); } return id; } //! \brief Return the id of the secondary aqueous species "label" //! //! Return no_species if "label" is not an aqueous species. //! A component (of the basis) is not considered as a secondary aqueous species. index_t aqueous_label_to_id(const std::string& label) { return data->aqueous.get_id(label); } //! \brief Safe version of 'aqueous_label_to_id //! throw an error if the compounds cannot be found index_t safe_aqueous_label_to_id(const std::string& label) { auto id = aqueous_label_to_id(label); if (id == no_species) { throw db_invalid_label(label+" is not an aqueous species !"); } return id; } //! \brief Return the id of the gas "label" //! //! Return no_species if "label" is not a gas index_t gas_label_to_id(const std::string& label) { return data->gas.get_id(label); } //! \brief Safe version of 'gast_label_to_id //! throw an error if the compounds cannot be found index_t safe_gas_label_to_id(const std::string& label) { auto id = gas_label_to_id(label); if (id == no_species) { throw db_invalid_label(label+" is not a gas !"); } return id; } protected: RawDatabasePtr data; //! The database }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATAABASE_MODULE_HPP diff --git a/src/database/oxydo_selector.cpp b/src/database/oxydo_selector.cpp index 85433f7..fd49513 100644 --- a/src/database/oxydo_selector.cpp +++ b/src/database/oxydo_selector.cpp @@ -1,89 +1,92 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "oxydo_selector.hpp" namespace specmicp { namespace database { void OxydoSelector::remove_half_cells(const std::vector& list_components) { std::vector list_id_components(list_components.size()); for (auto i=0; i& list_components) { remove_half_cells_secondary(&(data->aqueous), list_components); remove_half_cells_secondary(&(data->sorbed), list_components); remove_half_cells_secondary(&(data->gas), list_components); remove_half_cells_secondary(&(data->minerals), list_components); remove_half_cells_secondary(&(data->minerals_kinetic), list_components); } //! \brief Remove the half-cells reaction for the aqueous species void OxydoSelector::remove_half_cells_secondary( ReactiveSpeciesList* slist, const std::vector& list_components) { // first we select the species to remove std::vector to_remove(slist->size(), false); for (auto id: slist->range()) { if (slist->nu_ji(id, DataContainer::electron_index()) == 0.0) continue; for (const auto& component: list_components) { if (slist->nu_ji(id, component) != 0.0) to_remove[id] = true; } } // then we remove them, in two steps const auto nb_to_keep = std::count(to_remove.cbegin(), to_remove.cend(), false); auto new_j = 0; // 1) first we copy data in the beginning of the arrays for (index_t j: slist->range()) { if (to_remove[j]) continue; slist->move_erase(j, new_j); ++new_j; } specmicp_assert(new_j == nb_to_keep); // 2) then we resize the arrays slist->resize(nb_to_keep); slist->set_valid(); } } // end namespace database } // end namespace specmicp diff --git a/src/database/oxydo_selector.hpp b/src/database/oxydo_selector.hpp index 2b9a6e0..fb494de 100644 --- a/src/database/oxydo_selector.hpp +++ b/src/database/oxydo_selector.hpp @@ -1,64 +1,67 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_OXYDOSELECTOR_HPP #define SPECMICP_DATABASE_OXYDOSELECTOR_HPP //! \file mineral_selector.hpp select minerals in the database #include "module.hpp" namespace specmicp { namespace database { //! \brief Select equilibrum minerals in the database //! //! Keep only the solid phases that the user wants class OxydoSelector: public DatabaseModule { public: OxydoSelector(RawDatabasePtr thedata): DatabaseModule(thedata) {} void remove_half_cells(const std::vector& list_components); void remove_half_cells(const std::vector& list_components); private: //! \brief Remove the half-cells reaction corresponding to list_components in 'slist' void remove_half_cells_secondary( ReactiveSpeciesList* slist, const std::vector& list_components); }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_MINERALSELECTOR_HPP diff --git a/src/database/reader.cpp b/src/database/reader.cpp index 8a2a1ad..5b08051 100644 --- a/src/database/reader.cpp +++ b/src/database/reader.cpp @@ -1,625 +1,628 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "reader.hpp" #include "json/json.h" #include #include #include #include #include #include #include "utils/log.hpp" #define INDB_SECTION_BASIS "Basis" #define INDB_SECTION_AQUEOUS "Aqueous" #define INDB_SECTION_MINERALS "Minerals" #define INDB_SECTION_GAS "Gas" #define INDB_SECTION_SORBED "Sorbed" #define INDB_ATTRIBUTE_LABEL "label" #define INDB_ATTRIBUTE_ACTIVITY "activity" #define INDB_ATTRIBUTE_ACTIVITY_A "a" #define INDB_ATTRIBUTE_ACTIVITY_B "b" #define INDB_ATTRIBUTE_MOLARMASS "molar_mass" #define INDB_ATTRIBUTE_MOLARVOLUME "molar_volume" #define INDB_ATTRIBUTE_COMPOSITION "composition" #define INDB_ATTRIBUTE_LOGK "log_k" #define INDB_ATTRIBUTE_NBSITEOCCUPIED "nb_sites_occupied" #define INDB_ATTRIBUTE_FLAG_KINETIC "flag_kinetic" #define INDB_OPEN_DELIMITER_CHARGE '[' #define INDB_CLOSE_DELIMITER_CHARGE ']' #define INDB_ELECTRON "E[-]" #include namespace specmicp { namespace database { //! \brief Check if a mandatory section/attribute exists //! //! Throw db_invalid_syntax if not. inline void check_for_mandatory_value(const Json::Value& root, const std::string& attribute); //! \brief Return a mandatory section //! //! Throw db_invalid_syntax if the section does not exist inline Json::Value& get_mandatory_section(Json::Value& root, const std::string& section); // safe access to values std::string obtain_label(Json::Value& species); void obtain_composition(Json::Value& species, std::map& compo); scalar_t obtain_logk(Json::Value& species); bool is_kinetic(Json::Value& species); // void DataReader::parse(const std::string& filepath) { std::ifstream datafile(filepath, std::ifstream::binary); if (not datafile.is_open()) { ERROR << "Database not found : " << filepath; std::string message("Database not found : " + filepath); throw std::invalid_argument(message); } return parse(datafile); datafile.close(); } void DataReader::parse(std::istream& input ) { Json::Reader reader; Json::Value root; DEBUG << "Parsing database"; bool parsingSuccessful = reader.parse(input, root); if ( !parsingSuccessful ) { // report to the user the failure and their locations in the document. std::string message("Failed to parse configuration\n" + reader.getFormatedErrorMessages()); throw std::runtime_error(message); } m_electron_hash = m_hash_fn(INDB_ELECTRON); // Basis // ------ check_for_mandatory_value(root, INDB_SECTION_BASIS); parse_basis(root[INDB_SECTION_BASIS]); // Aqueous species // --------------- check_for_mandatory_value(root, INDB_SECTION_AQUEOUS); AqueousList alist; parse_aqueous(root[INDB_SECTION_AQUEOUS], alist); data->aqueous = std::move(alist); // Minerals // -------- check_for_mandatory_value(root, INDB_SECTION_MINERALS); MineralList minerals, minerals_kinetic; parse_minerals(root[INDB_SECTION_MINERALS], minerals, minerals_kinetic); data->minerals = std::move(minerals); data->minerals_kinetic = std::move(minerals_kinetic); // Gas // ---- GasList glist(0, data->nb_component()); if (root.isMember(INDB_SECTION_GAS)) parse_gas(root[INDB_SECTION_GAS], glist); else glist.set_valid(); data->gas = std::move(glist); // Sorbed species // -------------- SorbedList slist(0, data->nb_component()); if (root.isMember(INDB_SECTION_SORBED)) parse_sorbed(root[INDB_SECTION_SORBED], slist); else slist.set_valid(); data->sorbed = std::move(slist); } void DataReader::parse_basis(Json::Value& basis) { DEBUG << "Size basis : " << basis.size(); data->components = ComponentList(basis.size()); for (int id: data->components.range()) { Json::Value species = basis[id]; check_for_mandatory_value(species, INDB_ATTRIBUTE_LABEL); std::string label = obtain_label(species); if (id == water_id and label != water_label) { throw invalid_database("The first component should be "+water_label+"."); } else if (id == electron_id and label != electron_label) { throw invalid_database("The second component should be "+electron_label+"."); } auto is_already_in_the_database = data->components.get_id(label); if (is_already_in_the_database != no_species) throw invalid_database("Component : " + label + "is already in the database."); SPAM << "Parsing component : " << label; ComponentValues values; values.label = label; values.ionic_values.charge = charge_from_label(label); if (species.isMember(INDB_ATTRIBUTE_ACTIVITY)) { values.ionic_values.a_debye = species[INDB_ATTRIBUTE_ACTIVITY][INDB_ATTRIBUTE_ACTIVITY_A].asDouble(); values.ionic_values.b_debye = species[INDB_ATTRIBUTE_ACTIVITY][INDB_ATTRIBUTE_ACTIVITY_B].asDouble(); } check_for_mandatory_value(species, INDB_ATTRIBUTE_MOLARMASS); values.molar_mass = species[INDB_ATTRIBUTE_MOLARMASS].asDouble(); data->components.set_values(id, std::move(values)); } data->components.set_valid(); } void DataReader::parse_aqueous(Json::Value& aqueous, AqueousList& alist) { DEBUG << "Parse aqueous species"; alist = AqueousList(aqueous.size(), data->nb_component()); //const auto size = data->nb_aqueous(); for (auto id: alist.range()) { Json::Value& species = aqueous[static_cast(id)]; AqueousValues values; values.label = obtain_label(species); values.ionic_values.charge = charge_from_label(values.label); if (species.isMember(INDB_ATTRIBUTE_ACTIVITY)) { values.ionic_values.a_debye = species[INDB_ATTRIBUTE_ACTIVITY][INDB_ATTRIBUTE_ACTIVITY_A].asDouble(); values.ionic_values.b_debye = species[INDB_ATTRIBUTE_ACTIVITY][INDB_ATTRIBUTE_ACTIVITY_B].asDouble(); } values.logk = obtain_logk(species); alist.set_values(id, std::move(values)); // equation std::map compo; obtain_composition(species, compo); scalar_t test_charge {0.0}; std::map to_canonicalize; for (const auto& it: compo) { // component ? const auto search = data->components.get_id(it.first); if(search != no_species) { alist.set_nu_ji(id, search, it.second); test_charge += it.second*data->charge_component(search); } // aqueous species ? else { // in the document we parse ? const auto id_aq = alist.get_id(it.first); if (id_aq != no_species) { to_canonicalize.insert({id_aq, it.second}); test_charge += it.second*alist.charge(id_aq); } // cannot be found... else { throw db_invalid_syntax("Unknown species : '" + it.first + "' while parsing equations for " + alist.get_label(id) +"."); } } } if (test_charge != alist.charge(id)) { throw db_invalid_data("Total charge is not zero for aqueous species : '" + alist.get_label(id) + "' - Charge-decomposition - charge species : "+ std::to_string(test_charge - alist.charge(id) )+"."); } for (const auto& tocanon: to_canonicalize) { alist.canonicalize(id, tocanon.first, tocanon.second); } } alist.set_valid(); } void DataReader::parse_minerals(Json::Value& minerals, MineralList& minerals_list, MineralList& minerals_kinetic_list) { DEBUG << "Parse minerals"; index_t nb_mineral = minerals.size(); // find kinetic minerals int nb_kin = 0; for (int id=0; idnb_component()); minerals_kinetic_list = MineralList(nb_kin, data->nb_component()); // id for each class of minerals index_t id_in_eq=0; index_t id_in_kin=0; for (index_t id=0; id(id)]; //check if material is at equilibrium or governed by kinetics bool is_kin = is_kinetic(species); MineralValue value; value.label = std::move(obtain_label(species)); value.logk = obtain_logk(species); if (species.isMember(INDB_ATTRIBUTE_MOLARVOLUME)) { value.molar_volume = species[INDB_ATTRIBUTE_MOLARVOLUME].asDouble(); } else { // ###FIXME value.molar_volume = -1; } auto& mlist = is_kin?minerals_kinetic_list:minerals_list; auto& true_id = is_kin?id_in_kin:id_in_eq; mlist.set_values(true_id, std::move(value)); // equation // -------- std::map compo; obtain_composition(species, compo); double test_charge = 0; std::map to_canonicalize; for (const auto& it: compo) { auto idc = data->components.get_id(it.first); if(idc != no_species) { // this is a component mlist.set_nu_ji(true_id, idc, it.second); test_charge += it.second * data->charge_component(idc); } else { // this is an aqueous species auto idaq = data->aqueous.get_id(it.first); if (idaq != no_species) { to_canonicalize.insert({idaq, it.second}); test_charge += it.second * data->charge_aqueous(idaq); } else // or something we don't know { throw db_invalid_syntax("Unknown species : '" + it.first + "' while parsing equations for " + mlist.get_label(true_id) +"."); } } } if (test_charge != 0) { throw db_invalid_data("Total charge is not zero for mineral : '"+ mlist.get_label(true_id) + "' - total charge : "+std::to_string(test_charge)+"."); } // canonicalise for (const auto& tocanon: to_canonicalize) { mlist.canonicalize(true_id, data->aqueous, tocanon.first, tocanon.second); } // update index ++true_id; } specmicp_assert(id_in_kin == minerals_kinetic.size()); specmicp_assert(id_in_eq == minerals.size()); minerals_list.set_valid(); minerals_kinetic_list.set_valid(); } void DataReader::parse_gas(Json::Value& gas, GasList& glist) { DEBUG << "Parse gas"; glist = GasList(gas.size(), data->nb_component()); for (auto id: glist.range()) { Json::Value& species = gas[static_cast(id)]; GasValues values; values.label = obtain_label(species); auto is_already_in_the_database = data->gas.get_id(values.label); if (is_already_in_the_database != no_species) throw invalid_database("Component : " + values.label + "is already in the database."); values.logk = obtain_logk(species); glist.set_values(id, std::move(values)); // equation std::map compo; obtain_composition(species, compo); scalar_t test_charge = 0.0; std::map to_canonicalize; for (auto it: compo) { const auto idc = data->components.get_id(it.first); // component if(idc != no_species) { glist.set_nu_ji(id, idc, it.second); test_charge += it.second*data->charge_component(idc); } // aqueous species else { const auto idaq = data->aqueous.get_id(it.first); if (idaq != no_species) { to_canonicalize.insert({idaq, it.second}); test_charge += it.second*data->charge_aqueous(idaq); } else { throw db_invalid_syntax("Unknown species : '" + it.first + "' while parsing equations for " + data->gas.get_label(id) +"."); } } } if (test_charge != 0) { throw db_invalid_data("Total charge is not zero for gas '"+data->gas.get_label(id)+ "' : " + std::to_string(test_charge)+"."); } // canonicalise for (const auto& tocanon: to_canonicalize) { glist.canonicalize(id, data->aqueous, tocanon.first, tocanon.second); } } glist.set_valid(); } void DataReader::parse_sorbed(Json::Value& sorbed, SorbedList& slist) { DEBUG << "Parse sorbed species"; slist = SorbedList(sorbed.size(), data->nb_component()); for (auto id: slist.range()) { Json::Value& species = sorbed[static_cast(id)]; SorbedValues values; values.label = obtain_label(species); auto is_already_in_the_database = slist.get_id(values.label); if (is_already_in_the_database != no_species) throw invalid_database("Component : " + values.label + "is already in the database."); values.logk = obtain_logk(species); check_for_mandatory_value(species, INDB_ATTRIBUTE_NBSITEOCCUPIED); const auto nb_site_occupied = species[INDB_ATTRIBUTE_NBSITEOCCUPIED].asDouble(); if (nb_site_occupied < 0) { throw db_invalid_data("The number of sites occupied by a sorbed species must be positive. (Species : " + values.label + ", number of sites : " +std::to_string(nb_site_occupied) + ")"); } values.sorption_site_occupied = nb_site_occupied; slist.set_values(id, std::move(values)); std::map compo; obtain_composition(species, compo); double test_charge = 0; std::map to_canonicalize; for (auto it: compo) { const auto idc = data->components.get_id(it.first); if(idc != no_species) { slist.set_nu_ji(id, idc, it.second); test_charge += it.second*data->charge_component(idc); } else { const auto idaq = data->aqueous.get_id(it.first); if (idaq != no_species) { to_canonicalize.insert({idaq, it.second}); test_charge += it.second*data->charge_aqueous(idaq); } else { throw db_invalid_syntax("Unknown species : '" + it.first + "' while parsing equations for " + slist.get_label(id) +"."); } } } if (test_charge != 0) { throw db_invalid_data("Total charge is not zero for gas '"+slist.get_label(id)+ "' : " + std::to_string(test_charge)+"."); } // canonicalise for (const auto& tocanon: to_canonicalize) { slist.canonicalize(id, data->aqueous, tocanon.first, tocanon.second); } } slist.set_valid(); } void parse_equation(const std::string& equation, std::map &compo) { std::vector list_compo; boost::split(list_compo, equation, [](char input){return input == ',';}, boost::token_compress_on); for (auto it=list_compo.begin(); it!=list_compo.end(); ++it) { std::string& toparse = *it; double coeff = 0; boost::trim_all(toparse); unsigned int pos_end = 0; while (pos_end < toparse.size()) { if (std::isalpha(toparse[pos_end])) // or std::isblank(toparse[pos_end])) { break; } ++pos_end; } std::string label(toparse.substr(pos_end, toparse.size()-pos_end)); boost::trim_all(label); if (pos_end == 0) coeff =1; else if (pos_end == 1 and toparse[0] == '-') coeff=-1; else { std::string tofloat = toparse.substr(0, pos_end); while (pos_end > 1) { if ((tofloat[0] == '-' or tofloat[0] == '+') and std::isspace(tofloat[1]) ) { tofloat = tofloat[0] + tofloat.substr(2,pos_end-2); --pos_end; continue; } else { break; } } if ( tofloat[pos_end-1] == '-' ) {coeff = -1;} else if (tofloat[pos_end-1] == '+') {coeff = +1;} else {coeff = std::stof(tofloat);} } compo[label] = coeff; } } double charge_from_label(const std::string& label) { int sign=1; auto start= label.end(); auto stop = label.end(); for (auto it=label.begin(); it != label.end(); ++it) { if (*it == INDB_OPEN_DELIMITER_CHARGE) { start = it; } } if (start == label.end()) {return 0;} // no charge specified for (auto it=start+1; it != label.end(); ++it) { if (*it == INDB_CLOSE_DELIMITER_CHARGE) { stop = it; } } if (stop == label.end()) {throw db_invalid_syntax("Charge : missing closing delimiter for species : "+label+".");} start = start+1; if (stop == start) {return 0;} // nothing inside bracket // get the signs if (*(stop-1) == '-') { sign = -1; stop =stop-1; } else if (*(stop-1) == '+') { sign = +1; stop = stop-1; } if (stop == start) { return sign; // just the sign, |z|=1 } double charge; try { charge = sign*std::stof(std::string(start,stop)); } catch (std::invalid_argument&) { throw db_invalid_syntax("Charge : bad formatting for species :"+ label+"."); } return charge; } inline void check_for_mandatory_value(const Json::Value& root, const std::string& attribute) { if (not root.isMember(attribute)) { throw db_invalid_syntax("Missing : mandatory parameter '" + attribute +"'."); } } inline Json::Value& get_mandatory_section(Json::Value& root, const std::string& section) { check_for_mandatory_value(root, section); return root[section]; } std::string obtain_label(Json::Value& species) { check_for_mandatory_value(species, INDB_ATTRIBUTE_LABEL); return species[INDB_ATTRIBUTE_LABEL].asString(); } void obtain_composition(Json::Value& species, std::map& compo) { check_for_mandatory_value(species, INDB_ATTRIBUTE_COMPOSITION); parse_equation(species[INDB_ATTRIBUTE_COMPOSITION].asString(), compo); } scalar_t obtain_logk(Json::Value& species) { check_for_mandatory_value(species, INDB_ATTRIBUTE_LOGK); return species[INDB_ATTRIBUTE_LOGK].asDouble(); } bool is_kinetic(Json::Value& species) { bool is_kin {false}; if (species.isMember(INDB_ATTRIBUTE_FLAG_KINETIC)) { is_kin = species[INDB_ATTRIBUTE_FLAG_KINETIC].asBool(); } return is_kin; } } // end namespace specmicp } // end namespace chemy diff --git a/src/database/reader.hpp b/src/database/reader.hpp index 732aa89..d2d59dd 100644 --- a/src/database/reader.hpp +++ b/src/database/reader.hpp @@ -1,134 +1,137 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef DATABASE_READER_H #define DATABASE_READER_H //! \file reader.hpp Read the json database #include "json/json-forwards.h" #include "module.hpp" #include namespace specmicp { namespace database { //! \brief Read a json file containing a database //! //! This is a reader class, it does not transform //! (reduce to canonical form, swap the basis) the data class DataReader: public DatabaseModule { public: //! \brief Constructor //! //! @param filepath string containing the path to the database DataReader(const std::string& filepath): DatabaseModule() { parse(filepath); } //! \brief Constructor //! //! @param input input stream that contains the database DataReader(std::istream& input): DatabaseModule() { parse(input); } //! Return the databes RawDatabasePtr get_database() {return data;} //! \brief Parse the basis section //! //! Contains the list of primary species void parse_basis(Json::Value& basis_root); //! \brief Parse the aqueous section //! //! Contains the list of secondary species void parse_aqueous(Json::Value& aqueous_root, AqueousList& alist); //! \brief Parse the mineral section //! //! Contains the list of minerals void parse_minerals( Json::Value& minerals, MineralList &minerals_list, MineralList &minerals_kinetic_list ); //! \brief Parse the gas section void parse_gas(Json::Value& gas_root, GasList &glist); //! \brief Parse the sorbed species section void parse_sorbed(Json::Value& sorbed_root, SorbedList &slist); private: //! \brief Parse database //! //! Throw db_invalid_syntax if a syntax error was detected. //! Throws std::invalid_argument if the path to the database is not correct void parse(std::istream& input ); //! \brief Parse database //! //! Throw db_invalid_syntax if a syntax error was detected. //! Throws std::invalid_argument if the path to the database is not correct void parse(const std::string& filepath); //! \brief Parse the metadata section //! //! we don't do much with them for now.... void parse_metadata(Json::Value& root); std::hash m_hash_fn; std::size_t m_electron_hash; }; //! \brief Parse an equation void parse_equation(const std::string &equation, std::map& compo); //! \brief Get the charge of a species by parsing the label //! //! Examples : //! - neutral -> 0 //! - neutral[] -> 0 //! - charge[+] -> +1 //! - charge[-1] -> -1 //! - charge[+2] -> +2 //! - charge[2-] -> -2 double charge_from_label(const std::string& label); } // end namespace database } // end namespace specmicp #endif // DATABASE_READER_H diff --git a/src/database/selector.cpp b/src/database/selector.cpp index d20962b..c4c8c39 100644 --- a/src/database/selector.cpp +++ b/src/database/selector.cpp @@ -1,172 +1,176 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ + #include "selector.hpp" #include "aqueous_selector.hpp" namespace specmicp { namespace database { void DatabaseSelector::remove_component(const std::vector& id_component_to_remove) { analyse_component(id_component_to_remove); select_aqueous(id_component_to_remove); select_minerals(id_component_to_remove); select_minerals_kinetic(id_component_to_remove); if (data->nb_gas() != 0) select_gas(id_component_to_remove); select_sorbed(id_component_to_remove); select_components(); } void DatabaseSelector::analyse_component(const std::vector& id_component_to_remove) { for (auto it: id_component_to_remove) { if (it == DataContainer::water_index()) { throw std::invalid_argument("Water cannot be removed from the database"); } else if (it == DataContainer::electron_index()) { throw std::invalid_argument("The electron cannot be removed from the database"); } m_is_component_to_remove[it] = true; } m_nb_component_to_keep = data->nb_component() - id_component_to_remove.size(); } void DatabaseSelector::select_secondary( ReactiveSpeciesList* toselect, const std::vector& id_component_to_remove ) { // first we select which aqueous species we should remove std::vector to_remove(toselect->size(), false); for (index_t j: toselect->range()) { for (const auto& it: id_component_to_remove) { if (toselect->nu_ji(j, it) != 0.0) { to_remove[j] = true; break; } } } // then we remove them, in two steps const auto nb_to_keep = std::count(to_remove.cbegin(), to_remove.cend(), false); auto new_j = 0; // 1) first we copy data in the beginning of the arrays for (index_t j: toselect->range()) { if (to_remove[j]) continue; toselect->move_erase(j, new_j, m_is_component_to_remove); ++new_j; } specmicp_assert(new_j == nb_to_keep); // 2) then we resize the arrays toselect->resize(nb_to_keep, nb_component_to_keep()); toselect->set_valid(); // By doing in this order, we avoid bulk copy of arrays } void DatabaseSelector::select_aqueous(const std::vector& id_component_to_remove) { select_secondary(&(data->aqueous), id_component_to_remove); } void DatabaseSelector::select_minerals(const std::vector& id_component_to_remove) { select_secondary(&(data->minerals), id_component_to_remove); } void DatabaseSelector::select_minerals_kinetic(const std::vector& id_component_to_remove) { select_secondary(&(data->minerals_kinetic), id_component_to_remove); } void DatabaseSelector::select_gas(const std::vector& id_component_to_remove) { select_secondary(&(data->gas), id_component_to_remove); } void DatabaseSelector::select_sorbed(const std::vector& id_component_to_remove) { select_secondary(&(data->sorbed), id_component_to_remove); } void DatabaseSelector::select_components() { uindex_t new_i = 0; for (index_t i: data->range_component()) { if (is_component_to_remove(i)) continue; data->components.move_erase(i, new_i); ++new_i; } specmicp_assert(new_i == nb_component_to_keep()); data->components.resize(nb_component_to_keep()); data->components.set_valid(); } void DatabaseSelector::keep_only_component(const std::vector& id_to_keep) { // First build the list of components to remove std::vector id_to_remove; id_to_remove.reserve(data->nb_component() - id_to_keep.size()); for (index_t id: data->range_aqueous_component()) // avoid removing H2O and E[-] { auto search = std::find(id_to_keep.cbegin(), id_to_keep.cend(), id); if (search == id_to_keep.end()) id_to_remove.push_back(id); } // Then remove them remove_component(id_to_remove); } void DatabaseSelector::remove_all_gas() { data->gas = GasList(0, data->nb_component()); data->gas.set_valid(); } void DatabaseSelector::remove_all_sorbed() { data->sorbed = SorbedList(0, data->nb_component()); data->sorbed.set_valid(); } //! \brief Remove some specific aqueous species void DatabaseSelector::remove_aqueous(const std::vector& id_aqueous) { AqueousSelector(data).remove_aqueous(id_aqueous); } } // end namespace database } // end namespace specmicp diff --git a/src/database/selector.hpp b/src/database/selector.hpp index a46cdb4..60513e4 100644 --- a/src/database/selector.hpp +++ b/src/database/selector.hpp @@ -1,109 +1,112 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_SELECTOR_HPP #define SPECMICP_DATABASE_SELECTOR_HPP //! \file selector.hpp select species int the database #include #include "module.hpp" namespace specmicp { namespace database { //! \brief Select species in the database //! //! This is a special class with the only function is to remove some components from the database class DatabaseSelector: public DatabaseModule { public: DatabaseSelector(RawDatabasePtr thedata): DatabaseModule(thedata), m_is_component_to_remove(thedata->nb_component(), false) {} //! Remove compoment in the list "id_component_to_remove" void remove_component(const std::vector& id_component_to_remove); //! keep only components in the "id_to_keep" list void keep_only_component(const std::vector& id_to_keep); //! \brief Remove all gas phase void remove_all_gas(); //! \brief Remove all gas phase void remove_all_sorbed(); // //! \brief Remove all half-cell reactions // void remove_half_cells_reactions(); //! \brief Remove some specific aqueous species void remove_aqueous(const std::vector& id_aqueous); private: //! \brief Analyse wich component should be removed void analyse_component(const std::vector& id_component_to_remove); void select_secondary( ReactiveSpeciesList* toselect, const std::vector& id_component_to_remove ); //! \brief Select the correct aqueous species void select_aqueous(const std::vector& id_component_to_remove); //! \brief Select the correct minerals void select_minerals(const std::vector& id_component_to_remove); //! \brief Select the correct minerals governed by kinetics void select_minerals_kinetic(const std::vector& id_component_to_remove); //! \brief Select the gas phases void select_gas(const std::vector& id_component_to_remove); //! \brief Select the sorbed species void select_sorbed(const std::vector& id_component_to_remove); //! \brief Select components //! //! This should be the last operation void select_components(); //! \brief Return true if the component must be removed bool is_component_to_remove(index_t id) {return m_is_component_to_remove[id];} //! \brief Return the number of component to keep in the db uindex_t nb_component_to_keep() {return m_nb_component_to_keep;} std::vector m_is_component_to_remove; // true if component will be removed uindex_t m_nb_component_to_keep; // total number of component after the purging is done }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_SELECTOR_HPP diff --git a/src/database/species/aqueous_list.hpp b/src/database/species/aqueous_list.hpp index 495a136..d66cc33 100644 --- a/src/database/species/aqueous_list.hpp +++ b/src/database/species/aqueous_list.hpp @@ -1,170 +1,173 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_AQUEOUSLIST_HPP #define SPECMICP_DATABASE_AQUEOUSLIST_HPP #include "common.hpp" #ifndef SPECMICP_DATABASE_SPECIES_HPP #include "species.hpp" #endif #ifndef SPECMICP_DATABASE_IONICPARAMETERS_HPP #include "ionic_parameters.hpp" #endif //! \file aqueous_list.hpp //! \brief The list of aqueous species namespace specmicp { namespace database { //! \struct AqueousValues //! \brief Struct to initialize an aqueous species in the aqueous species list //! //! \ingroup database_species struct AqueousValues { std::string label; scalar_t logk; IonicModelValues ionic_values; }; //! \class AqueousList //! \brief The aqueous species //! //! This is the list of aqueous species in the system //! //! \ingroup database_species class AqueousList: public ReactiveSpeciesList { public: //! Initialize an empty list AqueousList() {} //! Initialize a list of 'siz' aqueous species with 'nb_components' components AqueousList(index_t size, index_t nb_components): ReactiveSpeciesList(size, nb_components), m_ionic_param(size) {} //! \name Size //! \brief Manage the size of the list // -------- //! @{ //! \brief Resize the list void resize(index_t size) override { ReactiveSpeciesList::resize(size); m_ionic_param.resize(size); } //! \brief Resize the list, adjust the number of components void resize(index_t size, index_t nb_components) override { ReactiveSpeciesList::resize(size, nb_components); m_ionic_param.resize(size); } //! @} //! \name Getter //! \brief Return values // ---------------------- //! @{ //! \brief Return the ionic size of component 'k' const scalar_t& a_debye(index_t k) const { return m_ionic_param.a_debye(k); } //! \brief Return the 'b-dot' parameter of component 'k' const scalar_t& b_debye(index_t k) const { return m_ionic_param.b_debye(k); } //! \brief Return the charge of component 'k' const scalar_t& charge(index_t k) const { return m_ionic_param.charge(k); } //! \brief Return the ionic model values of component 'k' IonicModelValues ionic_values(index_t k) const { return m_ionic_param.get_values(k); } //! @} //! \name Setter //! \brief Set values // ------------- //! @{ //! \brief Set the ionic model parameters void set_ionic_values(index_t k, const IonicModelValues& values) { m_ionic_param.set_values(k, values); } //! \brief Set the values //! \warning Do no set stoichiometric coefficients void set_values(index_t k, const AqueousValues& values) { set_label(k, values.label); set_logk(k, values.logk); m_ionic_param.set_values(k, values.ionic_values); } //! \brief Set the values //! \warning Do no set stoichiometric coefficients void set_values(index_t k, AqueousValues&& values) { set_label(k, std::move(values.label)); set_logk(k, values.logk); m_ionic_param.set_values(k, std::move(values.ionic_values)); } //! @} //! \name Move //! \brief Move species inside the list or to other lists // ------------ //! @{ //! \brief Move component 'old_ind' to 'new_ind' void move_erase(index_t old_ind, index_t new_ind) override { m_ionic_param.move_erase(old_ind, new_ind); ReactiveSpeciesList::move_erase(old_ind, new_ind); } //! \brief Move component 'old_ind' to 'new_ind' void move_erase(index_t old_ind, index_t new_ind, const std::vector& is_reactants_to_remove) override { m_ionic_param.move_erase(old_ind, new_ind); ReactiveSpeciesList::move_erase(old_ind, new_ind, is_reactants_to_remove); } //! @} //! \brief Add the aqueous species 'other_species' to 'k', to obtain a canonical system void canonicalize(index_t k, index_t other_species, scalar_t coeff) { add_species_to(k, other_species, coeff); } private: IonicModelParameters m_ionic_param; }; } // end namespace database } // end namespace specmicp #endif //SPECMICP_DATABASE_AQUEOUSLIST_HPP diff --git a/src/database/species/base_wrapper.cpp b/src/database/species/base_wrapper.cpp index 481603d..f349832 100644 --- a/src/database/species/base_wrapper.cpp +++ b/src/database/species/base_wrapper.cpp @@ -1,51 +1,54 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "base_wrapper.hpp" namespace specmicp { namespace database { //! \brief replace imformation of 'new_ind' by those contained in 'old_ind' void MatrixSpeciesWrapper::move_erase(index_t old_ind, index_t new_ind, const std::vector is_col_to_remove) { specmicp_assert(static_cast(is_col_to_remove.size()) == m_matrix.cols()); index_t new_col {0}; for (index_t col=0; col, Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_BASEWRAPPER_HPP #define SPECMICP_DATABASE_BASEWRAPPER_HPP #include "common.hpp" //! \file base_wrapper.hpp //! //! \brief Base wrapper around vectors and matrices //! //! These classes encapsulate an Eigen Matrix (or vector) //! //! \defgroup database_species namespace specmicp { namespace database { //! \class MatrixSpeciesWrapper //! \brief A wrapper around a matrix, to be used by a SpeciesList (or a derived class) instance //! //! \ingroup database_species Describing the species in the database class MatrixSpeciesWrapper { public: //! \brief Default constructor MatrixSpeciesWrapper() {} //! \brief Constructor initializing the matrix MatrixSpeciesWrapper(index_t size, index_t nb_cols): m_matrix(Matrix::Zero(size, nb_cols)) {} //! \name Size // ============ //! \brief Return and set the size of the matrix //! @{ //! \brief Return the number of rows in the matrix index_t size() const {return m_matrix.rows();} //! \brief Resize the matrix //! This is a resize only for the number of rows void resize(index_t size) { m_matrix.conservativeResize(size, Eigen::NoChange); } //! \brief Resize the matrix (both rows and colums) void resize(index_t rows, index_t cols) { m_matrix.conservativeResize(rows, cols); } // @} //! \name Getter // ============= //! \brief Return the values //! @{ //! \brief Return the element ['row', ['col'] const scalar_t& operator()(index_t row, index_t col) const { return m_matrix(row, col); } //! \brief Return a const reference to the matrix const Matrix& get_matrix() const { return m_matrix; } //! \brief Return the row of a matrix Eigen::MatrixBase::ConstRowXpr get_row(index_t k) const { return m_matrix.row(k); } //! \brief Return the element ['row','col'] const scalar_t& get_value(index_t row, index_t col) const { return m_matrix(row, col); } //! @} //! \name Setter // ============= //! \brief Set the values //! @{ //! \brief Add 'other' to row 'k' template void add_to_row(index_t k, const Eigen::MatrixBase& other) { m_matrix.row(k) += other; } //! \brief Multiply row 'k' by 'multiplier' template void multiply_by(const Eigen::MatrixBase& multiplier) { m_matrix = m_matrix*multiplier; } //! \brief Set the value of the matrix by copying 'init_matrix' template void set_matrix(const Eigen::MatrixBase& init_matrix) { m_matrix = init_matrix; } //! \brief Set the element ['row','col'] to 'value' void set_value(index_t row, index_t col, scalar_t value) { m_matrix(row, col) = value; } //! \brief Reset row 'k' void reset_row(index_t k) { m_matrix.row(k).setZero(); } //! @} //! \name Move // =========== //! \brief Move values inside, and outside, of the matrix //! @{ //! \brief replace imformation of 'new_ind' by those contained in 'old_ind' void move_erase(index_t old_ind, index_t new_ind) { m_matrix.row(new_ind) = m_matrix.row(old_ind); } //! \brief replace imformation of 'new_ind' by those contained in 'old_ind' void move_erase(index_t old_ind, index_t new_ind, const std::vector is_col_to_remove); //! \brief Move the row to another matrix void move_erase_to(index_t ind, MatrixSpeciesWrapper& other, index_t other_ind) { other.m_matrix.row(other_ind) = m_matrix.row(ind); m_matrix.row(ind).setZero(); } //! \brief Swap two rows void swap(index_t ind, MatrixSpeciesWrapper& other, index_t other_ind) { m_matrix.row(ind).swap(other.m_matrix.row(other_ind)); } //! @} private: Matrix m_matrix; }; //! \class VectorSpeciesWrapper //! \brief A wrapper around a vector //! //! \ingroup database_species class VectorSpeciesWrapper { public: //! \brief Default constructor VectorSpeciesWrapper() {} //! \brief Initialise the vector //! \param size initial size of the vector VectorSpeciesWrapper(index_t size): m_vector(Vector::Zero(size)) {} //! \name Size // ============ //! \brief Return and set the size of the vector //! @{ //! \brief Return the size of the vector index_t size() const {return m_vector.rows();} //! \brief Resize the vector void resize(index_t size) { m_vector.conservativeResize(size); } //! @} //! \name Getter // ============= //! \brief Return the values //! @{ //! \brief return the value of index k const scalar_t& operator()(index_t k) const { return m_vector(k); } //! \brief Return the inner product of the vector and 'other' template scalar_t dot(const Eigen::MatrixBase& other) const { return m_vector.dot(other); } //! \brief Return the value of index k const scalar_t& get_value(index_t k) const { return m_vector(k); } //! \brief Return the vector const Vector& get_vector() const { return m_vector; } //! @} //! \name Setter // ============= //! \brief Set the values //! @{ //! \brief add 'vector' template void add(const Eigen::MatrixBase& vector) { m_vector += vector; } //! \brief Multiply the vector by 'multiplier' template void multiply_by(const Eigen::MatrixBase& multiplier) { m_vector = m_vector*multiplier; } //! \brief Set the value at index k void set_value(index_t k, scalar_t value) { m_vector(k) = value; } //! \brief Copy 'vector' to the vector template void set_vector(const Eigen::MatrixBase& vector) { m_vector = vector; } //! \brief Apply a linear transformation to the vector template void transform(const Eigen::MatrixBase& transform_matrix) { specmicp_assert(transform_matrix.rows() == transform_matrix.cols()); m_vector = transform_matrix*m_vector; } //! @} //! \name Move // =========== //! \brief Move values inside, and outside, of the matrix //! @{ //! \brief Move value of old_ind at new_ind void move_erase(index_t old_ind, index_t new_ind) { m_vector(new_ind) = m_vector(old_ind); } //! \brief Move row 'ind' to 'other' at row 'other_ind' void move_erase_to(index_t ind, VectorSpeciesWrapper& other, index_t other_ind) { other.m_vector(other_ind) = m_vector(ind); m_vector(ind) = 0; } //! @} private: Vector m_vector; }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_BASEWRAPPER_HPP diff --git a/src/database/species/component_list.hpp b/src/database/species/component_list.hpp index 0aee603..92eef48 100644 --- a/src/database/species/component_list.hpp +++ b/src/database/species/component_list.hpp @@ -1,160 +1,163 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_COMPONENTLIST_HPP #define SPECMICP_DATABASE_COMPONENTLIST_HPP #include "common.hpp" #ifndef SPECMICP_DATABASE_SPECIES_HPP #include "species.hpp" #endif #ifndef SPECMICP_DATABASE_IONICPARAMETERS_HPP #include "ionic_parameters.hpp" #endif //! \file component_list.hpp A list of components, i.e the basis namespace specmicp { namespace database { //! \struct ComponentValues //! \brief Used for the initialization of a component //! //! \ingroup database_species struct ComponentValues { std::string label; scalar_t molar_mass; IonicModelValues ionic_values; }; //! \class ComponentList //! \brief The basis //! //! This is the list of components in the system //! It extends the species list by managing the ionic //! model parameters and the molar masses. //! //! \ingroup database_species class ComponentList: public SpeciesList { public: ComponentList() {} ComponentList(index_t size): SpeciesList(size), m_molar_mass(size), m_ionic_param(size) {} // Resize // ------ //! \brief Resize the basis void resize(index_t size) override { SpeciesList::resize(size); m_molar_mass.resize(size); m_ionic_param.resize(size); } // Getter // ====== //! \brief Return the molar mass of component k const scalar_t& molar_mass(index_t k) const { return m_molar_mass(k); } //! \brief Return the charge of component 'k' const scalar_t& charge(index_t k) const { return m_ionic_param.charge(k); } //! \brief Return the ionic size of component 'k' const scalar_t& a_debye(index_t k) const { return m_ionic_param.a_debye(k); } //! \brief Return the 'b-dot' parameter of component 'k' const scalar_t& b_debye(index_t k) const { return m_ionic_param.b_debye(k); } //! \brief Return the ionic model values of component 'k' IonicModelValues ionic_values(index_t k) const { return m_ionic_param.get_values(k); } // Setter // ------ //! \brief set the values for component 'k' void set_values(index_t k, const ComponentValues& values) { set_label(k, values.label); m_molar_mass.set_value(k, values.molar_mass); m_ionic_param.set_values(k, values.ionic_values); } //! \brief set the values for component 'k' void set_values(index_t k, ComponentValues&& values) { set_label(k, std::move(values.label)); m_molar_mass.set_value(k, values.molar_mass); m_ionic_param.set_values(k, values.ionic_values); } void set_ionic_values(index_t k, const IonicModelValues& values) { m_ionic_param.set_values(k, values); } //! \brief Return the molar mass of a compounts //! \param stoech a vector containing the stoichiometric coefficients template scalar_t molar_mass_compounds(const Eigen::MatrixBase& stoech) const { return m_molar_mass.dot(stoech); } //! \brief Transform the molar mass of the basis //! \param transform_matrix the linear operator to apply template void molar_mass_transform(const Eigen::MatrixBase& transform_matrix) { m_molar_mass.transform(transform_matrix); } // Move // ----- //! \brief Move component 'old_ind' to 'new_ind' void move_erase(index_t old_ind, index_t new_ind) override { m_molar_mass.move_erase(old_ind, new_ind); m_ionic_param.move_erase(old_ind, new_ind); SpeciesList::move_erase(old_ind, new_ind); } private: VectorSpeciesWrapper m_molar_mass; IonicModelParameters m_ionic_param; }; } // end namespace database } // end namespace specmicp #endif //SPECMICP_DATABASE_COMPONENTLIST_HPP diff --git a/src/database/species/gas_list.hpp b/src/database/species/gas_list.hpp index 2ddf1e1..abef49c 100644 --- a/src/database/species/gas_list.hpp +++ b/src/database/species/gas_list.hpp @@ -1,103 +1,106 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_GASLIST_HPP #define SPECMICP_DATABASE_GASLIST_HPP #include "common.hpp" #ifndef SPECMICP_DATABASE_SPECIES_HPP #include "species.hpp" #endif //! \file gas_list.hpp //! \brief The list of gas phases in the database. namespace specmicp { namespace database { //! \struct GasValues //! \brief Struct to initialize a gas in the gas list //! //! \ingroup database_species struct GasValues { std::string label; //!< Label of the gas scalar_t logk; //!< Log_10 of the equilibrium constant }; //! \class GasList //! \brief The gas list //! //! This is the list of gas in the system //! //! \ingroup database_species class GasList: public ReactiveSpeciesList { public: //! Initialize an empty list GasList() {} //! Initialize a list of 'siz' aqueous species with 'nb_components' components GasList(index_t size, index_t nb_components): ReactiveSpeciesList(size, nb_components) {} //! \name Setter //! \brief Set values // ------------- //! @{ //! \brief Set the values //! \warning Do no set stoichiometric coefficients void set_values(index_t k, const GasValues& values) { set_label(k, values.label); set_logk(k, values.logk); } //! \brief Set the values //! \warning Do no set stoichiometric coefficients void set_values(index_t k, GasValues&& values) { set_label(k, std::move(values.label)); set_logk(k, values.logk); } //! @} //! \brief Add the aqueous species 'other_species' to 'k', to obtain a canonical system void canonicalize( index_t ind, const AqueousList& aqueous, index_t aqueous_ind, scalar_t coeff ) { add_alien_species_to(ind, aqueous, aqueous_ind, coeff); } }; } // end namespace database } // end namespace specmicp #endif //SPECMICP_DATABASE_GASLIST_HPP diff --git a/src/database/species/ionic_parameters.hpp b/src/database/species/ionic_parameters.hpp index fc4ab6a..244c877 100644 --- a/src/database/species/ionic_parameters.hpp +++ b/src/database/species/ionic_parameters.hpp @@ -1,109 +1,112 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_IONICPARAMETERS_HPP #define SPECMICP_DATABASE_IONICPARAMETERS_HPP #ifndef SPECMICP_DATABASE_BASEWRAPPER_HPP #include "base_wrapper.hpp" #endif //! \file ionic_parameters.hpp //! \brief The ionic model parameters //! //! These parameters are needed for all (primary and secondary) //! aqueous species. namespace specmicp { namespace database { //! \struct IonicModelValues //! The set of main values for the ionic model //! This is used for the initialisation of an aqueous species. //! //! \ingroup database_species struct IonicModelValues { scalar_t charge {0.0}; scalar_t a_debye {0.0}; scalar_t b_debye {0.0}; IonicModelValues() {} IonicModelValues(scalar_t acharge, scalar_t adebye, scalar_t bdebye): charge(acharge), a_debye(adebye), b_debye(bdebye) {} }; //! \class IonicModelParameters //! \brief Class that contains the ionic model parameters //! //! This class is used for all (primary and secondary) aqueous species. //! //! \ingroup database_species class IonicModelParameters: public MatrixSpeciesWrapper { public: static constexpr index_t charge_ind = 0; //!< Column index of the charge static constexpr index_t adebye_ind = 1; //!< Column index of the ionic size parameter static constexpr index_t bdebye_ind = 2; //!< Column index of the b-dot parameter IonicModelParameters() {} IonicModelParameters(index_t size): MatrixSpeciesWrapper(size, 3) {} void resize_columns(index_t colums) = delete; //!< The number of columns is fixed void resize_matrix(index_t rows, index_t cols) = delete; //!< The number of columns is fixed //! \brief Return the charge const scalar_t& charge(index_t ind) const {return get_value(ind, charge_ind);} //! \brief Return the ionic size parameter const scalar_t& a_debye(index_t ind) const {return get_value(ind, adebye_ind);} //! \brief Return the b-dot parameter const scalar_t& b_debye(index_t ind) const {return get_value(ind, bdebye_ind);} //! \brief Set the values void set_values(index_t ind, const IonicModelValues& values) { set_value(ind, charge_ind, values.charge); set_value(ind, adebye_ind, values.a_debye); set_value(ind, bdebye_ind, values.b_debye); } //! \brief Return the ionic value IonicModelValues get_values(index_t ind) const { return IonicModelValues(charge(ind), a_debye(ind), b_debye(ind)); } }; } // end namespace database } // end namespace specmicp #endif //SPECMICP_DATABASE_IONICPARAMETERS_HPP diff --git a/src/database/species/mineral_list.hpp b/src/database/species/mineral_list.hpp index 7603b6c..52f5932 100644 --- a/src/database/species/mineral_list.hpp +++ b/src/database/species/mineral_list.hpp @@ -1,165 +1,168 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_SPECIES_MINERALLIST_HPP #define SPECMICP_DATABASE_SPECIES_MINERALLIST_HPP #include "common.hpp" #ifndef SPECMICP_DATABASE_SPECIES_HPP #include "species.hpp" #endif #ifndef SPECMICP_DATABASE_AQUEOUSLIST_HPP #include "aqueous_list.hpp" #endif //! \file mineral_list.hpp //! \brief A list of solid phases namespace specmicp { namespace database { //! \struct MineralValue //! Initializer struct for a solid phase //! //! \ingroup database_species struct MineralValue { std::string label; //!< The label scalar_t logk; //!< log_10 of the equilibrium constant scalar_t molar_volume; //!< The molar volume }; //! \class MineralList //! \brief A list of solid phases //! //! In addition to the basic features of a 'ReactiveSpeciesList' //! this class handles the molar volume of the solid phases. //! //! \ingroup database_species class MineralList: public ReactiveSpeciesList { public: MineralList() {} MineralList(index_t size, index_t nb_component): ReactiveSpeciesList(size, nb_component), m_molar_volume(size) {} // Getter // ------ //! \brief Return the molar volume const scalar_t& molar_volume(index_t k) const { return m_molar_volume(k); } // Setter // ------ //! \brief Initialise the solid phase at index_t k //! \warning Do no set stoichiometric coefficients void set_values(index_t k, const MineralValue& values) { set_label(k, values.label); set_logk(k, values.logk); m_molar_volume.set_value(k, values.molar_volume); } //! \brief Initialise the solid phase at index_t k //! \warning Do no set stoichiometric coefficients void set_values(index_t k, MineralValue&& values) { set_label(k, std::move(values.label)); set_logk(k, std::move(values.logk)); m_molar_volume.set_value(k, std::move(values.molar_volume)); } // Move // ---- //! \brief Move the solid phase at index 'old_ind' to 'new_ind' void move_erase(index_t old_ind, index_t new_ind) override { ReactiveSpeciesList::move_erase(old_ind, new_ind); m_molar_volume.move_erase(old_ind, new_ind); } //! \brief Move the solid phase at index 'old_ind' to 'new_ind' and removes components void move_erase( index_t old_ind, index_t new_ind, const std::vector& is_reactants_to_remove ) override { ReactiveSpeciesList::move_erase(old_ind, new_ind, is_reactants_to_remove); m_molar_volume.move_erase(old_ind, new_ind); } //! \brief Move solid phase 'ind' to 'other_ind' in the 'other' list void move_erase_to( index_t ind, MineralList& other, index_t other_ind ) { ReactiveSpeciesList::move_erase_to(ind, other, other_ind); m_molar_volume.move_erase_to(ind, other.m_molar_volume, other_ind); } // Resize // ------ //! \brief Resize the list void resize(index_t size) override { ReactiveSpeciesList::resize(size); m_molar_volume.resize(size); } //! \brief Resize the list and the stoichiometric coefficients matrix void resize(index_t size, index_t nb_component) override { ReactiveSpeciesList::resize(size, nb_component); m_molar_volume.resize(size); } // Misc // ---- //! \brief Add the aqueous species 'other_species' to 'k', to obtain a canonical system void canonicalize( index_t ind, const AqueousList& aqueous, index_t aqueous_ind, scalar_t coeff ) { add_alien_species_to(ind, aqueous, aqueous_ind, coeff); } private: VectorSpeciesWrapper m_molar_volume; }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_SPECIES_MINERALLIST_HPP diff --git a/src/database/species/sorbed_list.hpp b/src/database/species/sorbed_list.hpp index 32d1261..459134e 100644 --- a/src/database/species/sorbed_list.hpp +++ b/src/database/species/sorbed_list.hpp @@ -1,158 +1,161 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_SORBEDLIST_HPP #define SPECMICP_DATABASE_SORBEDLIST_HPP #include "common.hpp" #ifndef SPECMICP_DATABASE_SPECIES_HPP #include "species.hpp" #endif //! \file aqueous_list.hpp //! \brief The list of sorbed species //! //! This list stores the informations about sorbed species. namespace specmicp { namespace database { //! \struct SorbedValues //! \brief Struct to initialize a sorbed species in the sorbed species list //! //! \ingroup database_species struct SorbedValues { std::string label; scalar_t logk; index_t sorption_site_occupied; }; //! \class SorbedList //! \brief The sorbed species //! //! This is the list of sorbed species in the database //! //! \ingroup database_species class SorbedList: public ReactiveSpeciesList { public: //! Initialize an empty list SorbedList() {} //! Initialize a list of 'size' sorbed species with 'nb_components' components SorbedList(index_t size, index_t nb_components): ReactiveSpeciesList(size, nb_components), m_sorption_site(size) {} //! \name Size //! \brief Manage the size of the list // -------- //! @{ //! \brief Resize the list void resize(index_t size) override { ReactiveSpeciesList::resize(size); m_sorption_site.resize(size); } //! \brief Resize the list, adjust the number of components void resize(index_t size, index_t nb_components) override { ReactiveSpeciesList::resize(size, nb_components); m_sorption_site.resize(size); } //! @} //! \name Getter //! \brief Return values // ---------------------- //! @{ //! \brief Return the ionic size of component 'k' const scalar_t& nb_sorption_site_occupied(index_t k) const { return m_sorption_site(k); } //! @} //! \name Setter //! \brief Set values // ------------- //! @{ //! \brief Set the values //! \warning Do no set stoichiometric coefficients void set_values(index_t k, const SorbedValues& values) { set_label(k, values.label); set_logk(k, values.logk); m_sorption_site.set_value(k, values.sorption_site_occupied); } //! \brief Set the values //! \warning Do no set stoichiometric coefficients void set_values(index_t k, SorbedValues&& values) { set_label(k, std::move(values.label)); set_logk(k, values.logk); m_sorption_site.set_value(k, values.sorption_site_occupied); } //! @} //! \name Move //! \brief Move species inside the list or to other lists // ------------ //! @{ //! \brief Move component 'old_ind' to 'new_ind' void move_erase(index_t old_ind, index_t new_ind) override { m_sorption_site.move_erase(old_ind, new_ind); ReactiveSpeciesList::move_erase(old_ind, new_ind); } //! \brief Move component 'old_ind' to 'new_ind' void move_erase(index_t old_ind, index_t new_ind, const std::vector& is_reactants_to_remove) override { m_sorption_site.move_erase(old_ind, new_ind); ReactiveSpeciesList::move_erase(old_ind, new_ind, is_reactants_to_remove); } //! @} //! \brief Add the aqueous species 'other_species' to 'k', to obtain a canonical system void canonicalize( index_t ind, const AqueousList& aqueous, index_t aqueous_ind, scalar_t coeff ) { add_alien_species_to(ind, aqueous, aqueous_ind, coeff); } private: VectorSpeciesWrapper m_sorption_site; }; } // end namespace database } // end namespace specmicp #endif //SPECMICP_DATABASE_SORBEDLIST_HPP diff --git a/src/database/species/species.cpp b/src/database/species/species.cpp index 718d07e..66b6638 100644 --- a/src/database/species/species.cpp +++ b/src/database/species/species.cpp @@ -1,58 +1,61 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "species.hpp" namespace specmicp { namespace database { static std::hash hash_fn; //!< The hash function void SpeciesList::set_label(index_t ind, const std::string& label) { m_labels[ind] = label; m_hashes[ind] = hash_fn(label); } void SpeciesList::set_label(index_t ind, std::string&& label) { m_labels.emplace(m_labels.begin()+ind, std::move(label)); m_hashes[ind] = hash_fn(m_labels[ind]); } index_t SpeciesList::get_id(const std::string& label) const { if (label == "") return no_species; auto hash = hash_fn(label); auto searchit = std::find(m_hashes.cbegin(), m_hashes.cend(), hash); if (searchit == m_hashes.cend()) return no_species; // the species does not exist in the list return static_cast(searchit - m_hashes.cbegin()); } } // end namespace database } // end namespace specmicp diff --git a/src/database/species/species.hpp b/src/database/species/species.hpp index 49cc7df..8099a47 100644 --- a/src/database/species/species.hpp +++ b/src/database/species/species.hpp @@ -1,381 +1,384 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_SPECIES_HPP #define SPECMICP_DATABASE_SPECIES_HPP #include "common.hpp" #include "base_wrapper.hpp" //! \file species.hpp //! //! \brief The base wrappers describing a species list //! //! The two classes of this file are the basis for any list of species //! and are at the cores of the database and its algorithm. namespace specmicp { namespace database { //! \class SpeciesList //! \brief Base class for a species list //! //! Manage the labels, id and the size of a species list. //! //! \ingroup database_species class SpeciesList { public: //! \brief An empty list SpeciesList(): m_is_valid(false) {} //! \brief Initalise a list with 'size' species SpeciesList(index_t size): m_is_valid(false), m_size(size), m_labels(size), m_hashes(size) {} virtual ~SpeciesList() = default; //! \name Size //! \brief Manage the size of the list // --------------- //! @{ //! \brief Return the number of species in the list index_t size() const {return m_size;} //! \brief Reset the number of species in the list virtual void resize(index_t size) { m_size = size; m_labels.resize(size); m_hashes.resize(size); set_nonvalid(); } //! @} //! \name Getter //! \brief Return values // ------- //! @{ //! \brief Return the label of species const std::string& get_label(index_t ind) const {return m_labels[ind];} //! \brief Return the index of a species from the label //! \return the index of the species or -1 if the species does not exist index_t get_id(const std::string& label) const; //! \brief to iterate over the elements range_t range() const { return boost::irange((index_t) 0, m_size); } //! \brief Return true if the list is valid //! //! The validity flag is automatically turned off when rsize, move_erase or move_erase_to is use. //! The user must turn it on again by using the set_valid member //! //! \sa set_valid //! \sa set_nonvalid bool is_valid() const noexcept { return m_is_valid; } //! @} //! \name Setter //! \brief Set values // ------ //! @{ //! \brief Set the label of species 'ind' void set_label(index_t ind, const std::string& label); //! \brief Set the label of species 'ind' void set_label(index_t ind, std::string&& label); //! \brief Set the list to be nonvalid //! \sa is_valid //! \sa set_valid void set_nonvalid() noexcept {m_is_valid = false;} //! \brief Set the list to be valid //! \sa is_valid //! \sa set_nonvalid void set_valid() {m_is_valid = true;} //! \brief Erase values at 'ind' void reset(index_t ind) { m_labels[ind] = ""; m_hashes[ind] = 0; } //! @} //! \name Move species //! \brief Move species in the list or to another list // ------------- //! @{ //! \brief move species 'old_ind' to 'new_ind' and erase the previous species at 'new_ind' virtual void move_erase(index_t old_ind, index_t new_ind) { set_nonvalid(); m_labels[new_ind] = m_labels[old_ind]; m_hashes[new_ind] = m_hashes[old_ind]; } //! \brief move 'ind' to 'other' at 'other_ind' void move_erase_to(index_t ind, SpeciesList& other, index_t other_ind) { set_nonvalid(); other.set_nonvalid(); other.set_label(other_ind, std::move(get_label(ind))); reset(ind); } //! @} private: using hash_result_type = std::hash::result_type; //!< Result of the hash function bool m_is_valid; index_t m_size; //!< Size of the list std::vector m_labels; //!< Labels std::vector m_hashes; //!< List of hashes }; //! \class ReactiveSpeciesList //! \brief A list of reactive species //! //! This list extends 'SpeciesList' and add the managements of //! stoichiometric coefficients and equilibrium constant. //! \ingroup database_species class ReactiveSpeciesList: public SpeciesList { public: //! \brief Initialize an empty list ReactiveSpeciesList() {} //! \brief Initialize a list of size 'size' with 'nb_components' components ReactiveSpeciesList(index_t size, index_t nb_components): SpeciesList(size), m_nu_coeffs(size, nb_components), m_log_k(size) {} virtual ~ReactiveSpeciesList() = default; //! \name Size //! \brief Manage the size of the list // ----------- //! @{ //! \brief Resize void resize(index_t size) override { m_nu_coeffs.resize(size); m_log_k.resize(size); SpeciesList::resize(size); } //! \brief Resize the list and the number of components virtual void resize(index_t size, index_t nb_components) { m_nu_coeffs.resize(size, nb_components); m_log_k.resize(size); SpeciesList::resize(size); } //! @} //! \name Getter //! \brief Return values // ------ //! @{ //! \brief Return a const reference to the logk vector const Vector& get_logk_vector() const { return m_log_k.get_vector(); } //! \brief Return a const reference to the stoichiometric matrix const Matrix& get_nu_matrix() const { return m_nu_coeffs.get_matrix(); } //! \brief Return a const reference to a row of the stoichiometric coefficient matrix Eigen::MatrixBase::ConstRowXpr get_nu_row(index_t k) const { return m_nu_coeffs.get_row(k); } //! \brief Return the logK of species 'j' const scalar_t& logk(index_t j) const { return m_log_k(j); } //! \brief Return the stoichiometric coefficient of species j and component i const scalar_t& nu_ji(index_t j, index_t i) const { return m_nu_coeffs(j, i); } //! @} //! \name Setter //! \brief Set the values of the parameters // ---------- //! @{ //! \brief set a logk void set_logk(index_t j, scalar_t value) { m_log_k.set_value(j, value); } //! \brief Set the logk vector template void set_logk_vector(const Eigen::MatrixBase& vector) { specmicp_assert(vector.rows() == m_log_k.size); m_log_k.set_vector(vector); } //! \brief Set the stoehiometric coefficient of species 'j' and component 'i' to 'value' void set_nu_ji(index_t j, index_t i, scalar_t value) { m_nu_coeffs.set_value(j, i, value); } //! \brief Set the stoichiometric coefficient template void set_nu_matrix(const Eigen::MatrixBase& matrix) { specmicp_assert(matrix.rows() == size()); m_nu_coeffs.set_matrix(matrix); } //! \brief Switch the basis //! //! Reference : Bethke2008 template void switch_basis( const Eigen::MatrixBase& transform, const Eigen::MatrixBase& kswap) { m_nu_coeffs.multiply_by(transform); m_log_k.add(-get_nu_matrix()*kswap); } //! \brief Reset a row of the stoichiometric coefficient matrix void reset_nu_row(index_t k) { m_nu_coeffs.reset_row(k); } //! @} //! \name Adding species //! \brief 'Add' one species to the other //! Replace an aqueous species by its decomposition into components. //! This is typically use during the canonicalization of the database // -------------- //! @{ //! \brief Add the species 'species_to_add' to 'k' void add_species_to( index_t k, index_t species_to_add, scalar_t coeff ) { add_nu_species_to(k, species_to_add, coeff); add_logk_species_to(k, species_to_add, coeff); } //! \brief Add the species 'species_to_add' from 'other' to 'k' void add_alien_species_to( index_t k, const ReactiveSpeciesList& other, index_t species_to_add, scalar_t coeff ) { add_nu_alien_species_to(k, other, species_to_add, coeff); add_logk_alien_species_to(k, other, species_to_add, coeff); } //! @} //! \name Move operations //! \brief Move species in the list or to other list // ----- //! @{ //! \brief move species 'old_ind' to 'new_ind' and erase the previous species at 'new_ind' void move_erase(index_t old_ind, index_t new_ind) override { m_nu_coeffs.move_erase(old_ind, new_ind); m_log_k.move_erase(old_ind, new_ind); SpeciesList::move_erase(old_ind, new_ind); } //! \brief move species 'old_ind' to 'new_ind' and erase the previous species at 'new_ind' //! //! This is the method that need to be used to remove components in the database. virtual void move_erase(index_t old_ind, index_t new_ind, const std::vector& is_reactants_to_remove) { m_nu_coeffs.move_erase(old_ind, new_ind, is_reactants_to_remove); m_log_k.move_erase(old_ind, new_ind); SpeciesList::move_erase(old_ind, new_ind); } //! \brief Move species 'ind' to the list 'other' at 'other_ind' void move_erase_to(index_t ind, ReactiveSpeciesList& other, index_t other_ind) { SpeciesList::move_erase_to(ind, other, other_ind); m_nu_coeffs.move_erase_to(ind, other.m_nu_coeffs, other_ind); m_log_k.move_erase_to(ind, other.m_log_k, other_ind); } //! @} private: // methods //! \brief Add the logk of 'species_to_add' in 'other' at species 'k' void add_logk_alien_species_to( index_t k, const ReactiveSpeciesList& other, index_t species_to_add, scalar_t coeff ) { auto tmp = m_log_k(k) + coeff*other.m_log_k(species_to_add); m_log_k.set_value(k, tmp); } //! \brief Add the logk of species_to_add at species 'k' void add_logk_species_to( index_t k, index_t species_to_add, scalar_t coeff ) { auto tmp = m_log_k(k) + coeff*m_log_k(species_to_add); m_log_k.set_value(k, tmp); } //! \brief Add the stoichiometric coefficient of species_to_add at species 'k' void add_nu_alien_species_to( index_t k, const ReactiveSpeciesList& other, index_t species_to_add, scalar_t coeff ) { m_nu_coeffs.add_to_row(k, coeff*other.m_nu_coeffs.get_row(species_to_add)); } //! \brief Add the stoichiometric coefficient of species_to_add at species 'k' void add_nu_species_to( index_t k, index_t species_to_add, scalar_t coeff ) { m_nu_coeffs.add_to_row(k, coeff*m_nu_coeffs.get_row(species_to_add)); } private: // attributes MatrixSpeciesWrapper m_nu_coeffs; //!< The stoichiometric coefficients VectorSpeciesWrapper m_log_k; //!< The logk values }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_SPECIES_HPP diff --git a/src/database/switch_basis.cpp b/src/database/switch_basis.cpp index 4555638..4bac1f7 100644 --- a/src/database/switch_basis.cpp +++ b/src/database/switch_basis.cpp @@ -1,139 +1,142 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "switch_basis.hpp" #include #include namespace specmicp { namespace database { index_t BasisSwitcher::get_true_aqueous_index(index_t ind) { return ind - data->nb_component(); } void BasisSwitcher::swap_components(std::map& swap_to_make) { std::vector id_swap; id_swap.reserve(data->nb_component()); for (index_t i: data->range_component()) { id_swap.push_back(i); } for (const auto& it: swap_to_make) { if (it.first == electron_label) { throw std::invalid_argument("Basis switch : water cannot be swapped from basis"); } if (it.first == electron_label) { throw std::invalid_argument("Basis switch : electron cannot be swapped from basis"); } const index_t idc = safe_component_label_to_id(it.first); const index_t idaq = data->nb_component() + safe_aqueous_label_to_id(it.second); id_swap[idc] = idaq; } switch_basis(id_swap); } void BasisSwitcher::switch_basis(std::vector& new_basis) { Eigen::MatrixXd beta = Eigen::MatrixXd::Zero( data->nb_component(), data->nb_component()); Eigen::VectorXd kswap(data->nb_component()); // swap coefficients, build beta matrix and kswap for (index_t i: data->range_component()) { if (new_basis[i] >= data->nb_component()) { index_t j = get_true_aqueous_index(new_basis[i]); beta.row(i).segment(0, data->nb_component()) = data->aqueous.get_nu_row(j); data->aqueous.reset_nu_row(j); data->aqueous.set_nu_ji(j, i, 1.0); kswap(i) = data->logk_aqueous(j); data->aqueous.set_logk(j, 0.0); } else { beta(i, i) = 1.0; kswap(i) = 0.0; } } Matrix betainv = beta.inverse(); data->components.molar_mass_transform(beta); data->aqueous.switch_basis(betainv, kswap); swap_aq_param(new_basis); swap_labels(new_basis); // now do the minerals data->minerals.switch_basis(betainv, kswap); data->minerals_kinetic.switch_basis(betainv, kswap); // and the gases if (data->nb_gas() > 0) { data->gas.switch_basis(betainv, kswap); } // and sorbed species if (data->nb_sorbed() > 0) { data->sorbed.switch_basis(betainv, kswap); } } void BasisSwitcher::swap_aq_param(std::vector& new_basis) { for (index_t i: data->range_component()) { if(new_basis[i] >= data->nb_component()) { const index_t j = get_true_aqueous_index(new_basis[i]); const auto tmp = data->components.ionic_values(i); data->components.set_ionic_values(i, data->aqueous.ionic_values(j)); data->aqueous.set_ionic_values(j, tmp); } } } void BasisSwitcher::swap_labels(std::vector& new_basis) { for (index_t i: data->range_component()) { if (new_basis[i] >= data->nb_component()) { const index_t j = get_true_aqueous_index(new_basis[i]); const auto tmp = data->components.get_label(i); data->components.set_label(i, data->aqueous.get_label(j)); data->aqueous.set_label(j, tmp); } } } } // end namespace database } // end namespace specmicp diff --git a/src/database/switch_basis.hpp b/src/database/switch_basis.hpp index 290f6c1..5bb2ba2 100644 --- a/src/database/switch_basis.hpp +++ b/src/database/switch_basis.hpp @@ -1,73 +1,76 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DATABASE_SWITCHBASIS_HPP #define SPECMICP_DATABASE_SWITCHBASIS_HPP //! \file switch_basis.hpp Switch basis #include "module.hpp" #include namespace specmicp { namespace database { //! \brief Use this class to switch the basis of the database class BasisSwitcher: public DatabaseModule { public: BasisSwitcher(RawDatabasePtr thedata): DatabaseModule(thedata) {} //! \brief Switch the basis //! //! @param new_basis list of id of the new basis //! //! The new basis is a list of id, id = id_component for no swapping //! or id = id_aqueous + nb_component for swapping a secondary species void switch_basis(std::vector& new_basis); void swap_components(std::map& swap_to_make); private: //! \brief Return the true aqueous index index_t get_true_aqueous_index(index_t ind); //! \brief Swap aqueous parameters during a basis transformation void swap_aq_param(std::vector& new_basis); //! \brief Swap labels - called during a basis transformation void swap_labels(std::vector& new_basis); }; } // end namespace database } // end namespace specmicp #endif // SPECMICP_DATABASE_SWITCHBASIS_HPP diff --git a/src/dfpm/1dtransport/diffusion.cpp b/src/dfpm/1dtransport/diffusion.cpp index 0f0bd11..fcc72bd 100644 --- a/src/dfpm/1dtransport/diffusion.cpp +++ b/src/dfpm/1dtransport/diffusion.cpp @@ -1,223 +1,226 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "diffusion.hpp" #include "diffusion_parameters.hpp" #include "dfpm/meshes/mesh1d.hpp" namespace specmicp { namespace dfpm { // SaturatedDiffusion1D:: SaturatedDiffusion1D::SaturatedDiffusion1D( mesh::Mesh1DPtr the_mesh, std::shared_ptr parameters, std::vector list_bcs ): m_tot_ndf(the_mesh->nb_nodes()), m_mesh(the_mesh), m_param(parameters), m_internal_flow(Vector::Zero(m_tot_ndf)), m_external_flow(Vector::Zero(m_tot_ndf)) { number_equations(list_bcs); } void SaturatedDiffusion1D::number_equations(std::vector list_bcs) { m_id_equations = Eigen::VectorXi::Zero(m_tot_ndf); for (auto it=list_bcs.begin(); it!=list_bcs.end(); ++it) { m_id_equations(*it) = no_equation; } index_t neq = 0; for (index_t node: m_mesh->range_nodes()) { if (m_id_equations(node) == no_equation) continue; m_id_equations(node) = neq; ++ neq; } m_neq = neq; } void SaturatedDiffusion1D::compute_residuals( const Vector& displacement, const Vector& velocity, Vector& residual ) { m_internal_flow.setZero(); residual.resize(get_neq()); residual.setZero(); for (index_t element: m_mesh->range_elements()) { Vector elem_residuals(2); elem_residuals.setZero(); element_residuals(element, displacement, velocity, elem_residuals); for (index_t enode: m_mesh->range_nen()) { if (id_equation(m_mesh->get_node(element, enode)) == no_equation) continue; residual(id_equation(m_mesh->get_node(element, enode))) += elem_residuals(enode); } } } void SaturatedDiffusion1D::element_residuals( index_t element, const Vector& displacement, const Vector& velocity, Vector& elem_residuals ) { Eigen::Matrix jacob; Eigen::Matrix evelocity, edisplacement; scalar_t mass_coeff = -(m_mesh->get_volume_element(element)/2.0); const index_t node_0 = m_mesh->get_node(element, 0); const index_t node_1 = m_mesh->get_node(element, 1); const scalar_t porosity = (m_param->porosity(node_0) + m_param->porosity(node_1) )/2.0; const scalar_t diff_coeff = 1.0/(0.5/m_param->diffusion_coefficient(node_0) + 0.5/m_param->diffusion_coefficient(node_1)); const index_t dof_0 = node_0; const index_t dof_1 = node_1; scalar_t flux_coeff = -( m_mesh->get_face_area(element) / m_mesh->get_dx(element) // * porosity * diff_coeff ); jacob << 1.0, -1.0, -1.0, 1.0; jacob *= flux_coeff; evelocity << velocity(dof_0)* mass_coeff*m_param->porosity(node_0), velocity(dof_1)* mass_coeff*m_param->porosity(node_1); edisplacement << displacement(dof_0), displacement(dof_1); elem_residuals = jacob*edisplacement; m_internal_flow(dof_0) += elem_residuals(0); m_internal_flow(dof_1) += elem_residuals(1); for (index_t en: m_mesh->range_nen()) { elem_residuals(en) += evelocity(en); elem_residuals(en) += (m_mesh->get_volume_element(element)/2.0 *external_flow(m_mesh->get_node(element, en))); } } void SaturatedDiffusion1D::compute_jacobian( Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian, scalar_t alphadt ) { list_triplet_t jacob; const index_t estimation = m_mesh->nb_nodes()*(m_mesh->nen); jacob.reserve(estimation); for (index_t element: m_mesh->range_elements()) { element_jacobian(element, displacement, velocity, jacob, alphadt); } jacobian = Eigen::SparseMatrix(get_neq(), get_neq()); jacobian.setFromTriplets(jacob.begin(), jacob.end()); } void SaturatedDiffusion1D::element_jacobian( index_t element, Vector& displacement, Vector& velocity, list_triplet_t& jacobian, scalar_t alphadt) { Eigen::VectorXd element_residual_orig(Eigen::VectorXd::Zero(2)); element_residuals(element, displacement, velocity, element_residual_orig); for (index_t en: m_mesh->range_nen()) { Eigen::VectorXd element_residual(Eigen::VectorXd::Zero(2)); const index_t node = m_mesh->get_node(element, en); const index_t dof = node; const index_t idc = id_equation(dof); if (idc == no_equation) continue; const scalar_t tmp_v = velocity(dof); const scalar_t tmp_d = displacement(dof); scalar_t h = eps_jacobian*std::abs(tmp_v); if (h < 1e-4*eps_jacobian) h = eps_jacobian; velocity(dof) = tmp_v + h; h = velocity(dof) - tmp_v; displacement(dof) = tmp_d + alphadt*h; element_residuals(element, displacement, velocity, element_residual); velocity(dof) = tmp_v; displacement(dof) = tmp_d; for (index_t enr: m_mesh->range_nen()) { const index_t noder = m_mesh->get_node(element, enr); const index_t idr = id_equation(noder); if (idr == no_equation) continue; jacobian.push_back(triplet_t(idr, idc, (element_residual(enr) - element_residual_orig(enr))/h)); } } } void SaturatedDiffusion1D::update_solution(const Vector &update, scalar_t lambda, scalar_t alpha_dt, Vector &predictor, Vector &displacement, Vector &velocity ) { for (index_t node: m_mesh->range_nodes()) { const index_t id = id_equation(node); if (id == no_equation) continue; velocity(node) += lambda*update(id); } displacement = predictor + alpha_dt*velocity; } } // end namespace dfpm } // end namespace specmicp diff --git a/src/dfpm/1dtransport/diffusion.hpp b/src/dfpm/1dtransport/diffusion.hpp index 637ee4f..e8ddd52 100644 --- a/src/dfpm/1dtransport/diffusion.hpp +++ b/src/dfpm/1dtransport/diffusion.hpp @@ -1,137 +1,140 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DFPM_1DTRANSPORT_DIFFUSION_HPP #define SPECMICP_DFPM_1DTRANSPORT_DIFFUSION_HPP #include #include "common.hpp" #include "dfpm/types.hpp" #include "dfpmsolver/parabolic_program.hpp" #include "dfpm/meshes/mesh1dfwd.hpp" namespace specmicp { namespace dfpm { class SaturatedDiffusion1DParameters; class SaturatedDiffusion1D: public dfpmsolver::ParabolicProgram { public: SaturatedDiffusion1D( mesh::Mesh1DPtr the_mesh, std::shared_ptr parameters, std::vector list_bcs ); //! \brief Return the number of equations index_t get_neq() const {return m_neq;} //! \brief Return the number of degrees of freedom per node index_t get_ndf() const {return 1;} //! \brief Return the total number of degrees of freedom index_t get_tot_ndf() const {return m_tot_ndf;} //! \brief Return the id of the equation corresponding to the degree of freedom 'id_dof' //! //! Return 'no_equation' if no equation exist index_t id_equation(index_t id_dof) const {return m_id_equations(id_dof);} void element_residuals(index_t element, const Vector& displacement, const Vector& velocity, Vector& element_residual ); //! \brief Compute the residuals void compute_residuals(const Vector& displacement, const Vector& velocity, Vector& residual ); //! \brief Compute the jacobian void compute_jacobian(Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian, scalar_t alphadt ); void element_jacobian( index_t element, Vector& displacement, Vector& velocity, list_triplet_t& jacobian, scalar_t alphadt); //! \brief Update the solutions void update_solution(const Vector& update, scalar_t lambda, scalar_t alpha_dt, Vector& predictor, Vector& displacement, Vector& velocity); //! \brief Apply boundary conditions to the velocity vector //! //! by default do nothing. void apply_bc(scalar_t dt, const Vector& displacement, Vector& velocity) {} //! \brief Return the value of the external flow for dof 'id_dof' scalar_t external_flow(index_t id_dof) const {return m_external_flow(id_dof);} //! \brief Return a reference to the value of the external flow for dof 'id_dof' scalar_t& external_flow(index_t id_dof) {return m_external_flow(id_dof);} //! \brief Return a reference to the vector of external flow Vector& external_flow() {return m_external_flow;} private: void number_equations(std::vector list_bcs); index_t m_tot_ndf; index_t m_neq; Eigen::VectorXi m_id_equations; mesh::Mesh1DPtr m_mesh; std::shared_ptr m_param; Vector m_internal_flow; Vector m_external_flow; }; } // end namespace dfpm } // end namespace specmicp #endif // SPECMICP_DFPM_1DTRANSPORT_DIFFUSION_HPP diff --git a/src/dfpm/1dtransport/diffusion_parameters.hpp b/src/dfpm/1dtransport/diffusion_parameters.hpp index d01c2a3..7898ebb 100644 --- a/src/dfpm/1dtransport/diffusion_parameters.hpp +++ b/src/dfpm/1dtransport/diffusion_parameters.hpp @@ -1,54 +1,57 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DFPM_1DTRANSPORT_DIFFUSIONPARAMETERS_HPP #define SPECMICP_DFPM_1DTRANSPORT_DIFFUSIONPARAMETERS_HPP #include "common.hpp" namespace specmicp { namespace dfpm { struct SaturatedDiffusion1DParameters { Vector porosity; Vector diffusion_coefficient; SaturatedDiffusion1DParameters(index_t nb_nodes): porosity(nb_nodes), diffusion_coefficient(nb_nodes) {} }; } // end namespace dfpm } // end namespace specmicp #endif // SPECMICP_DFPM_1DTRANSPORT_DIFFUSIONPARAMETERS_HPP diff --git a/src/dfpm/mesh.hpp b/src/dfpm/mesh.hpp index 421af96..51049da 100644 --- a/src/dfpm/mesh.hpp +++ b/src/dfpm/mesh.hpp @@ -1,32 +1,36 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ + #include "meshes/uniform_mesh1d.hpp" #include "meshes/axisymmetric_uniform_mesh1d.hpp" #include "meshes/axisymmetric_mesh1d.hpp" #include "meshes/generic_mesh1d.hpp" diff --git a/src/dfpm/meshes/axisymmetric_mesh1d.hpp b/src/dfpm/meshes/axisymmetric_mesh1d.hpp index 4edea05..27e5920 100644 --- a/src/dfpm/meshes/axisymmetric_mesh1d.hpp +++ b/src/dfpm/meshes/axisymmetric_mesh1d.hpp @@ -1,155 +1,158 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DFPM_MESHES_AXISYMMETRICMESH1D_HPP #define SPECMICP_DFPM_MESHES_AXISYMMETRICMESH1D_HPP #include "mesh1d.hpp" namespace specmicp { namespace mesh { //! \brief A generic Axisymmetric 1D mesh class AxisymmetricMesh1D: public Mesh1D { public: const index_t radius = 0; const index_t cell_vol_0 = 1; const index_t cell_vol_1 = 2; //! \brief Build an axisymmetric 1D mesh //! //! \param radius is a vector of the position of the nodes //! \param height is the height of the sample (or depth) AxisymmetricMesh1D(Vector radius, scalar_t height): Mesh1D(radius.rows()), m_height(height), m_data(radius.rows(), 3), m_face_radius(radius.rows()-1) { // radius m_data.col(0) = radius; // Radius of the faces for (index_t element=0; element( std::make_shared(radius, height)); } //! \brief Factory method to build a pointer to a uniform axisymmetric 1D mesh //! //! \param nb_nodes number of nodes in the mesh //! \param radius of the first node (biggest radius in the mesh) //! \param dx length of an element //! \param height is the height of the sample (or depth) //! //! Note: this method buil an AxisymmetricMesh1D instance while //! the specmicp::mesh::axisymmetric_uniform_mesh1d method build a //! specmicp::mesh::AxisymmetricUniformMesh1D instance. inline Mesh1DPtr uniform_axisymmetric_mesh1d(index_t nb_nodes, scalar_t radius, scalar_t dx, scalar_t height) { Vector radius_s(nb_nodes); for (index_t node=0; node( std::make_shared(radius_s, height)); } } // end namespace mesh } // end namespace specmicp #endif // SPECMICP_DFPM_MESHES_AXISYMMETRICMESH1D_HPP diff --git a/src/dfpm/meshes/axisymmetric_uniform_mesh1d.hpp b/src/dfpm/meshes/axisymmetric_uniform_mesh1d.hpp index e510941..56b5504 100644 --- a/src/dfpm/meshes/axisymmetric_uniform_mesh1d.hpp +++ b/src/dfpm/meshes/axisymmetric_uniform_mesh1d.hpp @@ -1,124 +1,127 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_MESHES_AXISYMMETRICMESH1D_HPP #define SPECMICP_REACTMICP_MESHES_AXISYMMETRICMESH1D_HPP #include "mesh1d.hpp" // \file axisymmetric_uniform_mesh1d.hpp Uniform axisymmetric 1D mesh namespace specmicp { namespace mesh { //! \brief A uniform 1D mesh class AxisymmetricUniformMesh1D: public Mesh1D { public: AxisymmetricUniformMesh1D(index_t nb_nodes, scalar_t radius, scalar_t height): Mesh1D(nb_nodes), m_radius(radius), m_radius_int(0.0), m_dx(radius/(nb_nodes-1)), m_height(height) {} AxisymmetricUniformMesh1D(index_t nb_nodes, scalar_t radius, scalar_t dx, scalar_t height): Mesh1D(nb_nodes), m_radius(radius), m_radius_int(radius-(nb_nodes-1)*dx), m_dx(dx), m_height(height) {} scalar_t get_radius_node(index_t node) { return m_radius-m_dx*node; } //! Return the radius of a face of an element scalar_t get_radius_face(index_t element) { return get_radius_node(get_node(element, 1))+m_dx/2; } scalar_t get_position(index_t node) {return get_radius_node(node);} scalar_t get_dx(index_t _) {return m_dx;} scalar_t get_face_area(index_t element) { return 2*M_PI*get_radius_face(element)*m_height;} scalar_t get_volume_element(index_t element) {return M_PI*m_height*( std::pow(get_radius_node(get_node(element, 0)),2) - std::pow(get_radius_node(get_node(element, 1)),2)) ;} scalar_t get_volume_cell(index_t node) { if (node ==0) return M_PI*m_height*(std::pow(m_radius,2)-std::pow(get_radius_face(0),2)); else if (node == nb_nodes()-1) if (m_radius_int == 0.0) return M_PI*m_height*std::pow(m_dx/2.0,2); else return M_PI*m_height*(std::pow(get_radius_face(node-1),2) - std::pow(m_radius_int,2)); else return M_PI*m_height*(std::pow(get_radius_face(node-1),2) - std::pow(get_radius_face(node),2)); } scalar_t get_volume_cell_element(index_t element, index_t enode) { if (enode == 0) { return M_PI*m_height*(std::pow(get_radius_node(get_node(element,enode)),2) - std::pow(get_radius_face(element),2)); } else { return M_PI*m_height*(std::pow(get_radius_face(element),2) - std::pow(get_radius_node(get_node(element,enode)),2)); } } private: scalar_t m_radius; scalar_t m_radius_int; scalar_t m_dx; scalar_t m_height; }; //! \brief Factory method to build a pointer to a uniform 1D mesh inline Mesh1DPtr axisymmetric_uniform_mesh1d(index_t nb_nodes, scalar_t radius, scalar_t height) { return std::static_pointer_cast( std::make_shared(nb_nodes, radius, height)); } //! \brief Factory method to build a pointer to a uniform 1D mesh inline Mesh1DPtr axisymmetric_uniform_mesh1d(index_t nb_nodes, scalar_t radius, scalar_t dx, scalar_t height) { return std::static_pointer_cast( std::make_shared(nb_nodes, radius, dx, height)); } } // end namespace mesh } // end namespace specmicp #endif // SPECMICP_REACTMICP_MESHES_AXISYMMETRICMESH1D_HPP diff --git a/src/dfpm/meshes/generic_mesh1d.hpp b/src/dfpm/meshes/generic_mesh1d.hpp index 5de7b33..248fe24 100644 --- a/src/dfpm/meshes/generic_mesh1d.hpp +++ b/src/dfpm/meshes/generic_mesh1d.hpp @@ -1,124 +1,127 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DFPM_MESHES_GENERICMESH1D_HPP #define SPECMICP_DFPM_MESHES_GENERICMESH1D_HPP #include "mesh1d.hpp" namespace specmicp { namespace mesh { //! \brief A generic 1D mesh class GenericMesh1D: public Mesh1D { public: const index_t coord = 0; const index_t cell_vol_0 = 1; const index_t cell_vol_1 = 2; //! \brief Build an axisymmetric 1D mesh //! //! \param radius is a vector of the position of the nodes //! \param height is the height of the sample (or depth) GenericMesh1D(Vector coords, scalar_t section): Mesh1D(coords.rows()), m_section(section), m_data(coords.rows(), 4), m_face_coord(coords.rows()-1) { // radius m_data.col(coord) = coords; // Radius of the faces for (index_t element=0; element( std::make_shared(coords, section)); } } // end namespace mesh } // end namespace specmicp #endif // SPECMICP_DFPM_MESHES_GENERICMESH1D_HPP diff --git a/src/dfpm/meshes/mesh1d.hpp b/src/dfpm/meshes/mesh1d.hpp index da2e4af..c807181 100644 --- a/src/dfpm/meshes/mesh1d.hpp +++ b/src/dfpm/meshes/mesh1d.hpp @@ -1,92 +1,95 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_MESH_MESH1D_HPP #define SPECMICP_REACTMICP_MESH_MESH1D_HPP #include "common.hpp" #include namespace specmicp { namespace mesh { //! AbstractBase class for a 1D mesh class Mesh1D { public: const index_t nen = 2; //!< Number of elemental nodes Mesh1D(index_t nb_nodes): m_nb_nodes(nb_nodes) {} virtual ~Mesh1D() {} //! \brief Return the number of elements index_t nb_elements() {return m_nb_nodes-1;} //! \brief Return the number of nodes index_t nb_nodes() {return m_nb_nodes;} //! \brief Return the node from local nod enumber and element index_t get_node(index_t element, index_t index) { specmicp_assert(index < nen); return element+index; } //! \brief Return the position (meaning may vary with the mesh) of the node virtual scalar_t get_position(index_t node) = 0; //! \brief Return the length of an element virtual scalar_t get_dx(index_t element) = 0; //! \brief Return the area of the face at the middle of an element virtual scalar_t get_face_area(index_t element) = 0; //! \brief Return the volume of an element virtual scalar_t get_volume_element(index_t element) = 0; //! \brief Return the volume of a cell (element of the dual mesh) virtual scalar_t get_volume_cell(index_t node) = 0; //! virtual scalar_t get_volume_cell_element(index_t element, index_t node) = 0; //! \brief Range over the elements range_t range_elements() {return boost::irange((index_t) 0, nb_elements());} //! \brief Range over the nodes range_t range_nodes() {return boost::irange((index_t) 0, nb_nodes());} //! \brief Range over the elemental nodes range_t range_nen() {return boost::irange((index_t) 0, nen);} private: index_t m_nb_nodes; //!< Number of elements }; //! \brief type of a pointer to a mesh //! //! This is a smart pointer allowing the mesh to be shared freely using Mesh1DPtr = std::shared_ptr; } // end namespace mesh } // end namespace specmicp #endif // SPECMICP_REACTMICP_MESH_MESH1D_HPP diff --git a/src/dfpm/meshes/mesh1dfwd.hpp b/src/dfpm/meshes/mesh1dfwd.hpp index 9a96ee1..15f2c10 100644 --- a/src/dfpm/meshes/mesh1dfwd.hpp +++ b/src/dfpm/meshes/mesh1dfwd.hpp @@ -1,46 +1,49 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_MESH_MESH1DFWD #define SPECMICP_REACTMICP_MESH_MESH1DFWD #include // define the forward declaration of a 1D mesh namespace specmicp { namespace mesh { class Mesh1D; using Mesh1DPtr = std::shared_ptr; } // end namespace mesh } // end namespace specmicp #endif // SPECMICP_REACTMICP_MESH_MESH1DFWD diff --git a/src/dfpm/meshes/uniform_mesh1d.hpp b/src/dfpm/meshes/uniform_mesh1d.hpp index 01de348..665b662 100644 --- a/src/dfpm/meshes/uniform_mesh1d.hpp +++ b/src/dfpm/meshes/uniform_mesh1d.hpp @@ -1,72 +1,76 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ + #ifndef SPECMICP_REACTMICP_MESH_UNIFORMMESH1D_HPP #define SPECMICP_REACTMICP_MESH_UNIFORMMESH1D_HPP #include "mesh1d.hpp" // \file uniform_mesh1d.hpp Uniform 1D mesh namespace specmicp { namespace mesh { //! \brief A uniform 1D mesh class UniformMesh1D: public Mesh1D { public: UniformMesh1D(index_t nb_nodes, scalar_t dx, scalar_t cross_section): Mesh1D(nb_nodes), m_dx(dx), m_crosssection(cross_section) {} scalar_t get_position(index_t node) {return m_dx*node;} scalar_t get_dx(index_t _) {return m_dx;} scalar_t get_face_area(index_t _) { return m_crosssection;} scalar_t get_volume_element(index_t _) {return m_dx*m_crosssection;} scalar_t get_volume_cell(index_t node) { if (node ==0 or node == nb_nodes()-1) return m_dx*m_crosssection/2; else return m_dx*m_crosssection; } scalar_t get_volume_cell_element(index_t element, index_t enode) { return m_dx*m_crosssection/2; } private: scalar_t m_dx; scalar_t m_crosssection; }; //! \brief Factory method to build a pointer to a uniform 1D mesh inline Mesh1DPtr uniform_mesh1d(index_t nb_nodes, scalar_t dx, scalar_t cross_section) { return std::static_pointer_cast(std::make_shared(nb_nodes, dx, cross_section)); } } // end namespace mesh } // end namespace specmicp #endif // SPECMICP_REACTMICP_MESH_UNIFORMMESH1D_HPP diff --git a/src/dfpm/types.hpp b/src/dfpm/types.hpp index 7f0b895..3a3ee40 100644 --- a/src/dfpm/types.hpp +++ b/src/dfpm/types.hpp @@ -1,46 +1,49 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DFPM_TYPES_HPP #define SPECMICP_DFPM_TYPES_HPP #include "common.hpp" #include "Eigen/SparseCore" #include namespace specmicp { namespace dfpm { using triplet_t = Eigen::Triplet; using list_triplet_t = std::vector; } // end namespace dfpm } // end namespace specmicp #endif // SPECMICP_DFPM_TYPES_HPP diff --git a/src/dfpmsolver/dfpm_program.hpp b/src/dfpmsolver/dfpm_program.hpp index ec9ad59..1740d80 100644 --- a/src/dfpmsolver/dfpm_program.hpp +++ b/src/dfpmsolver/dfpm_program.hpp @@ -1,65 +1,68 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DFPMSOLVER_DFPMPROGRAM_HPP #define SPECMICP_DFPMSOLVER_DFPMPROGRAM_HPP #include "common.hpp" namespace specmicp { namespace dfpmsolver { //! \brief Base class for a program template class DFPMProgram { public: //! \brief Return a pointer to the true object Derived* derived() {static_cast(this);} //! \brief Return the number of equations index_t get_neq() const {return derived()->get_neq();} //! \brief Return the number of degrees of freedom per node index_t get_ndf() const {return derived()->get_ndf();} //! \brief Return the total number of degrees of freedom index_t get_tot_ndf() const {return derived()->get_tot_ndf();} //! \brief Return the id of the equation corresponding to the degree of freedom 'id_dof' //! //! Return 'no_equation' if no equation exist index_t id_equation(index_t id_dof) const {return derived()->id_equation(id_dof);} }; } // end namespace dfpmsolver } // end namespace specmicp #endif // SPECMICP_DFPMSOLVER_DFPMPROGRAM_HPP diff --git a/src/dfpmsolver/driver.hpp b/src/dfpmsolver/driver.hpp index 7551049..5a9f961 100644 --- a/src/dfpmsolver/driver.hpp +++ b/src/dfpmsolver/driver.hpp @@ -1,135 +1,138 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DFPMSOLVER_DRIVER_HPP #define SPECMICP_DFPMSOLVER_DRIVER_HPP #include "common.hpp" namespace specmicp { namespace dfpmsolver { //! \brief Base class for a driver //! //! Options should be a subclass of DriverOptions //! Performance should be a subclass of DriverPerformance //! template class Driver { public: Driver(Program& the_program): m_program(the_program), m_options(), m_scaling_is_initialized(false) { } Driver(Program& the_program, Options some_options): m_program(the_program), m_options(some_options), m_scaling_is_initialized(false) { } // basic program management // ------------------------ //! Return the program Program& program() {return m_program;} //! Return the number of equations index_t get_neq() {return m_program.get_neq();} // common process // -------------- //! \brief rescale the update if needed //! //! Return the step length scalar_t is_step_too_long(Vector& update); // options // ------- //! \brief Return a read/write reference to the options Options& get_options() {return m_options;} //! \brief Return a read-only reference to the options const Options& get_options() const {return m_options;} // performance // ----------- //! \brief Return a const reference to the performance const Performance& get_perfs() const {return m_performance;} // Scaling // ------- void initialize_scaling() { if (not m_scaling_is_initialized) { m_scaling.resize(get_neq()); m_scaling.setOnes(); } } void set_scaling(const Vector& scale) { specmicp_assert(scale.rows() == get_neq()); m_scaling = scale; m_scaling_is_initialized = true; } const Vector& scaling() const {return m_scaling;} scalar_t scaling(index_t id_eq) const {return m_scaling(id_eq);} protected: //! \brief Read/write access to the performance Performance& get_perfs() {return m_performance;} private: Program& m_program; //!< The program Performance m_performance; //!< The performance Options m_options; //!< The options Vector m_scaling; //!< Scaling factor bool m_scaling_is_initialized; }; } // end namespace dfpmsolver } // end namespace specmicp // implementation // ============== #include "driver.inl" #endif // SPECMICP_DFPMSOLVER_DRIVER_HPP diff --git a/src/dfpmsolver/driver.inl b/src/dfpmsolver/driver.inl index 90f7f88..02cca47 100644 --- a/src/dfpmsolver/driver.inl +++ b/src/dfpmsolver/driver.inl @@ -1,51 +1,54 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "driver.hpp" // syntaxic coloration only namespace specmicp { namespace dfpmsolver { template scalar_t Driver::is_step_too_long(Vector& update) { double steplength = (scaling().asDiagonal()*update).norm(); if (steplength > get_options().maximum_step_length) { get_perfs().maximum_step_taken = true; update = (get_options().maximum_step_length / steplength) * update; steplength = get_options().maximum_step_length; } return steplength; } } // end namespace dfpmsolver } // end namespace specmicp diff --git a/src/dfpmsolver/driver_structs.hpp b/src/dfpmsolver/driver_structs.hpp index 38653c9..2e3cd53 100644 --- a/src/dfpmsolver/driver_structs.hpp +++ b/src/dfpmsolver/driver_structs.hpp @@ -1,96 +1,99 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DFPMSOLVER_DRIVERSTRUCTS_HPP #define SPECMICP_DFPMSOLVER_DRIVERSTRUCTS_HPP #include "common.hpp" #include "utils/sparse_solvers/sparse_solver_structs.hpp" namespace specmicp { namespace dfpmsolver { //! \brief Options of a driver //! struct DriverOptions { scalar_t residuals_tolerance; //!< Tolerance for the residual scalar_t absolute_tolerance; //!< Absolute tolerance for the residual scalar_t step_tolerance; //!< Tolerance for the minimum step length scalar_t threshold_stationary_point; //!< if ||R||>threshold, the point is classified as stationary int maximum_iterations; //!< Maximum iterations allowed scalar_t maximum_step_length; //!< Maximum step length allowed int max_iterations_at_max_length; //!< Maximum number of iterations at maximum step length scalar_t coeff_accept_newton_step; //!< Accept Newton step if enough progress is made sparse_solvers::SparseSolver sparse_solver; //!< The sparse solver to use DriverOptions(): residuals_tolerance(5e-5), absolute_tolerance(1e-12), step_tolerance(1e-10), threshold_stationary_point(1e-4), maximum_iterations(200), maximum_step_length(1e3), max_iterations_at_max_length(50), coeff_accept_newton_step(0.9), sparse_solver(sparse_solvers::SparseSolver::SparseQR) {} }; //! \brief Performance of a driver struct DriverPerformance { int nb_call_residuals; int nb_call_jacobian; int nb_iterations; int nb_consecutive_max_step_taken; int nb_max_step_taken; bool maximum_step_taken; scalar_t current_residual; scalar_t absolute_residual; scalar_t current_update; DriverPerformance(): nb_call_residuals(0), nb_call_jacobian(0), nb_iterations(0), nb_consecutive_max_step_taken(0), nb_max_step_taken(0), maximum_step_taken(0), current_residual(0.0), absolute_residual(0.0), current_update(0.0) {} }; } // end namespace dfpmsolver } // end namespace specmicp #endif // SPECMICP_DFPMSOLVER_DRIVERSTRUCTS_HPP diff --git a/src/dfpmsolver/parabolic_driver.hpp b/src/dfpmsolver/parabolic_driver.hpp index 9e64070..05af05e 100644 --- a/src/dfpmsolver/parabolic_driver.hpp +++ b/src/dfpmsolver/parabolic_driver.hpp @@ -1,182 +1,185 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DFPMSOLVER_PARABOLICDRIVER_HPP #define SPECMICP_DFPMSOLVER_PARABOLICDRIVER_HPP #include "common.hpp" #include "utils/sparse_solvers/sparse_solver.hpp" #include "driver.hpp" #include "parabolic_structs.hpp" namespace specmicp { namespace dfpmsolver { //! \brief The parabolic driver //! //! Parabolic driver for finite element programs template class ParabolicDriver: public Driver { public: using base=Driver; using base::program; using base::get_neq; using base::get_options; using base::get_perfs; using base::scaling; using base::initialize_scaling; ParabolicDriver(Program& the_program): Driver(the_program), m_velocity(Vector::Zero(the_program.get_tot_ndf())), m_solver(nullptr) {} //! \brief Solve a timestep of length dt ParabolicDriverReturnCode solve_timestep(scalar_t dt, Vector& displacement); //! \brief Restart the current timestep ParabolicDriverReturnCode restart_timestep(Vector& displacement); //! \brief Check if the solution has been found ParabolicDriverReturnCode check_convergence(); //! \brief Compute the residuals void compute_residuals(const Vector& displacement, Vector& residual) { compute_residuals(displacement, m_velocity, residual); } //! \brief Compute the residuals void compute_residuals(const Vector& displacement, const Vector& velocity, Vector& residual) { program().compute_residuals(displacement, velocity, residual); get_perfs().nb_call_residuals += 1; } //! \brief Compute the jacobian void compute_jacobian(Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian ); //! \brief Return the norm of the current residuals double norm_residuals() {return m_residuals.norm();} //! \brief Read/Write reference to the velocity vector const Vector& get_velocity() const {return m_velocity;} Vector& velocity() {return m_velocity;} void set_velocity(Vector& velocity_vector); //! \brief Reset the Sparse solver //! This function should be called when a new solver need to be used void reset_solver() {return m_solver.reset(nullptr);} //! \brief Call this function if the pattern of the jacobian has changed void jacobian_pattern_has_changed() {reset_solver();} //! \brief Initialize the computation void initialize_timestep(scalar_t dt, Eigen::VectorXd& displacement); //! \brief Strang Linesearch //! //! ref : //! - Matthies et al. (1979) //! - JHP course notes ParabolicLinesearchReturnCode strang_linesearch( Vector& update, Vector& displacements, scalar_t& lambda ); scalar_t residuals_0() {return m_norm_0;} private: void reset_velocity(); //! \brief Backtracking Linesearch //! //! ref : //! - Algo A6.3.1 : Dennis and Schnabel (1983) //! - Nocedal & Wrigth (2006) ParabolicLinesearchReturnCode backtracking_linesearch( Vector& update, Vector& displacements, scalar_t& lambda_out ); //! Update the variables in displacement void update_variable( const Vector& update, scalar_t lambda, Vector& displacement ); //! \brief Set the predictor void set_predictor(Vector& displacement); //! \brief perform the linesearch ParabolicDriverReturnCode linesearch( Vector &update, Vector &displacements ); //! Compute the residuals for the linesearch double compute_residuals_linesearch( Vector& update, scalar_t lambda, Vector& displacement ); double compute_residuals_strang_linesearch( Vector &update, scalar_t lambda, Vector &displacement ); scalar_t update_norm(const Vector& update); double m_norm_0; double m_current_dt; Eigen::VectorXd m_gradient; Eigen::VectorXd m_velocity; Eigen::VectorXd m_residuals; Eigen::VectorXd m_predictor; Eigen::SparseMatrix m_jacobian; sparse_solvers::SparseSolverPtr, Vector, Vector> m_solver; bool m_velocity_is_initialized; }; } // end namespace dfpmsolver } // end namespace specmicp // implementation // ============== #include "parabolic_driver.inl" #endif // SPECMICP_DFPMSOLVER_PARABOLICDRIVER_HPP diff --git a/src/dfpmsolver/parabolic_driver.inl b/src/dfpmsolver/parabolic_driver.inl index 0025ee7..7b282d4 100644 --- a/src/dfpmsolver/parabolic_driver.inl +++ b/src/dfpmsolver/parabolic_driver.inl @@ -1,510 +1,513 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "parabolic_driver.hpp" // for syntaxic coloration only #include "utils/log.hpp" //#include "utils/sparse_solver.hpp" namespace specmicp { namespace dfpmsolver { template void ParabolicDriver::compute_jacobian(Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian ) { program().compute_jacobian(displacement, velocity, jacobian, get_options().alpha*m_current_dt); jacobian = jacobian*scaling().asDiagonal(); jacobian.makeCompressed(); get_perfs().nb_call_jacobian += 1; } template ParabolicDriverReturnCode ParabolicDriver::solve_timestep(scalar_t dt, Eigen::VectorXd& displacement) { initialize_timestep(dt, displacement); return restart_timestep(displacement); } template void ParabolicDriver::initialize_timestep(scalar_t dt, Eigen::VectorXd& displacement) { initialize_scaling(); m_residuals = Eigen::VectorXd::Zero(get_neq()); m_current_dt = dt; set_predictor(displacement); reset_velocity(); program().apply_bc(dt, displacement, m_velocity); compute_residuals(displacement, m_velocity, m_residuals); m_norm_0 = norm_residuals(); get_perfs().nb_iterations = 0; } template void ParabolicDriver::set_predictor(Vector& displacement) { if (get_options().alpha < 1) m_predictor = displacement + (1-get_options().alpha)*m_current_dt*m_velocity; else m_predictor = displacement; } template scalar_t ParabolicDriver::update_norm(const Vector& update) { // l-∞ scaled norm scalar_t norm = 0.0; for (index_t dof=0; dof ParabolicDriverReturnCode ParabolicDriver::restart_timestep(Vector& displacement) { ParabolicDriverReturnCode return_code = ParabolicDriverReturnCode::NotConvergedYet; //m_solver.reset(nullptr); Eigen::VectorXd update(get_neq()); update.setZero(); get_perfs().current_update = 0; bool force_recompute_jacobian = true; while (return_code == ParabolicDriverReturnCode::NotConvergedYet) { compute_residuals(displacement, m_velocity, m_residuals); get_perfs().absolute_residual = m_residuals.norm(); get_perfs().current_residual = m_residuals.norm()/m_norm_0; get_perfs().current_update = update_norm(update); DEBUG << " NB iterations : " << get_perfs().nb_iterations << " - res : " << get_perfs().current_residual << " - update : " << get_perfs().current_update; return_code = check_convergence(); if (return_code != ParabolicDriverReturnCode::NotConvergedYet) break; if (m_solver == nullptr) { m_solver = sparse_solvers::get_sparse_solver< Eigen::SparseMatrix, Vector, Vector>(get_options().sparse_solver); compute_jacobian(displacement, m_velocity, m_jacobian); m_solver->analyse_pattern(m_jacobian); m_solver->decompose(m_jacobian); force_recompute_jacobian =false; } else if (force_recompute_jacobian or get_perfs().nb_iterations % get_options().quasi_newton == 0) { compute_jacobian(displacement, m_velocity, m_jacobian); m_solver->decompose(m_jacobian); } get_perfs().nb_iterations += 1; m_gradient = m_jacobian.transpose()*m_residuals; sparse_solvers::SparseSolverReturnCode retcode = m_solver->solve_scaling(m_residuals, scaling(), update); if (retcode != sparse_solvers::SparseSolverReturnCode::Success) { ERROR << "Error when solving linear system : " << (int) retcode << std::endl; return ParabolicDriverReturnCode::ErrorLinearSystem; } //if (update.norm() < get_options().step_tolerance) return_code = ParabolicDriverReturnCode::ErrorMinimized; //else return_code = linesearch(update, displacement); } return return_code; } template ParabolicDriverReturnCode ParabolicDriver::check_convergence() { ParabolicDriverReturnCode termcode = ParabolicDriverReturnCode::NotConvergedYet; const int nb_iterations = get_perfs().nb_iterations; const scalar_t norm_residuals = get_perfs().current_residual; const scalar_t norm_update = get_perfs().current_update; //std::cout << "Residuals : " << nb_iterations << " - " << norm_residuals/m_norm_0 << std::endl; DEBUG << "Residuals : " << nb_iterations << " - " << norm_residuals/m_norm_0; if (norm_residuals < get_options().residuals_tolerance) { termcode = ParabolicDriverReturnCode::ResidualMinimized; } else if (get_perfs().absolute_residual < get_options().absolute_tolerance) { termcode = ParabolicDriverReturnCode::ResidualMinimized; } else if (nb_iterations > 0 and norm_update > 0.0 and norm_update < 1.01*get_options().step_tolerance) { if (norm_residuals > get_options().threshold_stationary_point) { ERROR << "Stationary point detected !"; termcode = ParabolicDriverReturnCode::StationaryPoint; } WARNING << "Error is minimized - may indicate a stationnary point"; termcode = ParabolicDriverReturnCode::ErrorMinimized; } else if (nb_iterations > get_options().maximum_iterations) { ERROR << "Maximum number of iteration reached (" << get_options().maximum_iterations << ")"; termcode = ParabolicDriverReturnCode::MaxIterations; } else if (get_perfs().maximum_step_taken) { get_perfs().nb_consecutive_max_step_taken += 1; get_perfs().nb_max_step_taken += 1; if (get_perfs().nb_consecutive_max_step_taken == get_options().max_iterations_at_max_length) { ERROR << "Divergence detected - Maximum step length taken two many times"; termcode = ParabolicDriverReturnCode::MaxStepTakenTooManyTimes; } } else { get_perfs().nb_consecutive_max_step_taken = 0; } get_perfs().return_code = termcode; return termcode; } template double ParabolicDriver::compute_residuals_linesearch( Vector &update, scalar_t lambda, Vector &displacement ) { Eigen::VectorXd velocity(m_velocity); Eigen::VectorXd residual = Eigen::VectorXd::Zero(get_neq()); program().update_solution(update, lambda, get_options().alpha*m_current_dt, m_predictor, displacement, velocity); compute_residuals(displacement, velocity, residual); return 0.5*residual.squaredNorm(); } template double ParabolicDriver::compute_residuals_strang_linesearch( Vector &update, scalar_t lambda, Vector &displacement ) { Eigen::VectorXd velocity(m_velocity); Eigen::VectorXd residual = Eigen::VectorXd::Zero(get_neq()); program().update_solution(update, lambda, get_options().alpha*m_current_dt, m_predictor, displacement, velocity); compute_residuals(displacement, velocity, residual); return update.dot(residual); } template void ParabolicDriver::update_variable( const Vector& update, scalar_t lambda, Vector& displacement ) { program().update_solution(update, lambda, get_options().alpha*m_current_dt, m_predictor, displacement, m_velocity); } template ParabolicDriverReturnCode ParabolicDriver::linesearch( Vector &update, Vector &displacements ) { base::is_step_too_long(update); get_perfs().maximum_step_taken = false; scalar_t lambda; ParabolicLinesearchReturnCode retcode; switch (get_options().linesearch) { case ParabolicLinesearch::Bactracking: retcode = backtracking_linesearch(update, displacements, lambda); break; case ParabolicLinesearch::Strang: retcode = strang_linesearch(update, displacements, lambda); break; default: throw std::runtime_error("Linesearch type for Parabolic driver is not recognized"); break; } if (retcode != ParabolicLinesearchReturnCode::Success) { return ParabolicDriverReturnCode::LinesearchFailed; } update_variable(update, lambda, displacements); update *= lambda; return ParabolicDriverReturnCode::NotConvergedYet; } namespace internal { //! \brief Return true if a and b have the same sign inline bool have_same_sign(double a, double b) { return (std::copysign(1., a) * std::copysign(1., b) > 0); } } // end namespace internal template ParabolicLinesearchReturnCode ParabolicDriver::strang_linesearch( Vector& update, Vector& displacements, scalar_t& lambda ) { DEBUG << "Strang linesearch"; Eigen::VectorXd xp(displacements); const scalar_t s_tol = 0.5; const scalar_t s_max = 2.0; const int lin_max = 10; scalar_t s_b = 0.0; scalar_t g_b = 0.5*m_residuals.squaredNorm(); scalar_t s_a = 1.0; scalar_t g_a = compute_residuals_strang_linesearch(update, 1.0, xp); scalar_t newtlen = (scaling().asDiagonal()*update).norm(); // const scalar_t s_r = s_a; const scalar_t g_r = g_a; if (std::abs(g_a) <= s_tol*std::abs(g_b)) { DEBUG << "Skip linesearch "; lambda = 1.0; if (lambda == 1.0 and (newtlen > 0.99 * get_options().maximum_step_length)) { get_perfs().maximum_step_taken = true; } return ParabolicLinesearchReturnCode::Success; } while (internal::have_same_sign(g_a, g_b) and s_a < s_max) { s_b = s_a; s_a = 2*s_a; g_b = g_a; g_a = compute_residuals_strang_linesearch(update, s_a, xp); } scalar_t g_ = g_a; scalar_t g_0 = g_a; scalar_t s = s_a; int l; for (l=0; l= g_r) { WARNING << "Failed to find better update in Strang linesearch"; //lambda = 0.1*s_r; return backtracking_linesearch(update, displacements, lambda); } lambda = s_a; if (lambda == 1.0 and (newtlen > 0.99 * get_options().maximum_step_length)) { get_perfs().maximum_step_taken = true; } return ParabolicLinesearchReturnCode::Success; } template ParabolicLinesearchReturnCode ParabolicDriver::backtracking_linesearch( Vector& update, Vector& displacements, scalar_t& lambda_out ) { // References // ---------- // - Algo A6.3.1 : Dennis and Schnabel (1983) // - Nocedal & Wrigth (2006) DEBUG << "Linesearch"; Eigen::VectorXd xp(displacements); double fcp; int retcode = 2; // 2 not converged, 1 problem, 0 success const scalar_t alpha = 1e-4; scalar_t newtlen = (scaling().asDiagonal()*update).norm(); scalar_t init_slope = m_gradient.dot(update); const scalar_t rellength = update_norm(update); const scalar_t minlambda = get_options().step_tolerance / rellength; scalar_t lambda = 1.0; scalar_t lambda_prev = lambda; scalar_t merit_value = 0.5*m_residuals.squaredNorm(); // new residual fcp = compute_residuals_linesearch(update, lambda, xp); // Skip linesearch if enough progress is done // ------------------------------------------ if (fcp < get_options().coeff_accept_newton_step *merit_value) { DEBUG << "Skip linesearch "; lambda_out = 1.0; return ParabolicLinesearchReturnCode::Success; } // The linesearch // -------------- scalar_t fc = merit_value; scalar_t fcp_prev; int cnt = 0; do { SPAM << "cnt : " < 0.99 * get_options().maximum_step_length)) { get_perfs().maximum_step_taken = true; } break; } else if (lambda < minlambda) { retcode = 0; lambda = minlambda; //retcode = 1; break; } else { //WARNING << "denom : " << fcp - fc -init_slope; // Select a new step length // - - - - - - - - - - - - double lambdatmp; if (cnt == 0) { // only a quadratic at the first lambdatmp = - init_slope / (2*(fcp - fc -init_slope)); } else { const scalar_t factor = 1.0 /(lambda - lambda_prev); const scalar_t x1 = fcp - fc - lambda*init_slope; const scalar_t x2 = fcp_prev - fc - lambda_prev*init_slope; const scalar_t a = factor * ( x1/(lambda*lambda) - x2/(lambda_prev*lambda_prev)); const scalar_t b = factor * ( -x1*lambda_prev/(lambda*lambda) + x2*lambda/(lambda_prev*lambda_prev)); if (a == 0) { // cubic interpolation is in fact a quadratic interpolation lambdatmp = - init_slope/(2*b); } else { const scalar_t disc = b*b-3*a*init_slope; lambdatmp = (-b+std::sqrt(disc))/(3*a); } if (lambdatmp > 0.5*lambda ) lambdatmp = 0.5*lambda; } //WARNING << "lambdatmp : " << lambdatmp; lambda_prev = lambda; fcp_prev = fcp; if (lambdatmp < 0.1*lambda) { lambda = 0.1 * lambda; } else { lambda = lambdatmp; } } if (not std::isfinite(lambda)) { ERROR << "Lambda is non finite - we stop"; return ParabolicLinesearchReturnCode::Divergence; } fcp = compute_residuals_linesearch(update, lambda, xp); //xp.velocity = x.velocity; ++cnt; } while(retcode == 2 and cnt < 50); //WARNING << "Lambda : " << lambda << " - iterations : " << cnt; if (cnt == 50) { ERROR << "Too much linesearch iterations ! We stop"; return ParabolicLinesearchReturnCode::MaximumIterations; } lambda_out = lambda; switch (retcode) { case 0: return ParabolicLinesearchReturnCode::Success; break; case 1: return ParabolicLinesearchReturnCode::LambdaTooSmall; default: return ParabolicLinesearchReturnCode::NotSupposedToHappen; break; } } template void ParabolicDriver::set_velocity(Vector& velocity_vector) { m_velocity.resize(program().get_tot_ndf()); m_velocity.setZero(); for (index_t dof=0; dof void ParabolicDriver::reset_velocity() { for (index_t dof=0; dof, Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DFPMSOLVER_PARABOLICPROGRAM_HPP #define SPECMICP_DFPMSOLVER_PARABOLICPROGRAM_HPP #include "common.hpp" #include #include "dfpm_program.hpp" namespace specmicp { namespace dfpmsolver { //! Concept class for a program template class ParabolicProgram: DFPMProgram> { public: Derived* derived() {static_cast(this);} //! \brief Compute the residuals void compute_residuals(const Vector& displacement, const Vector& velocity, Vector& residual ) { derived()->compute_residuals(displacement, velocity, residual); } //! \brief Compute the jacobian void compute_jacobian(Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian, scalar_t alphadt ) { derived()->compute_jacobian(displacement, velocity, jacobian, alphadt); } //! \brief Update the solutions void update_solution(const Vector& update, scalar_t lambda, scalar_t alpha_dt, Vector& predictor, Vector& displacement, Vector& velocity) { derived()->update_solution(update, lambda, alpha_dt, predictor, displacement, velocity); } //! \brief Apply boundary conditions to the velocity vector //! //! by default do nothing. void apply_bc(scalar_t dt, const Vector& displacement, Vector& velocity) {} }; } // end namespace dfpmsolver } // end namespace specmicp #endif // SPECMICP_DFPMSOLVER_PARABOLICPROGRAM_HPP diff --git a/src/dfpmsolver/parabolic_structs.hpp b/src/dfpmsolver/parabolic_structs.hpp index 544a82a..e566628 100644 --- a/src/dfpmsolver/parabolic_structs.hpp +++ b/src/dfpmsolver/parabolic_structs.hpp @@ -1,97 +1,100 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_DFPMSOLVER_PARABOLICSTRUCTS_HPP #define SPECMICP_DFPMSOLVER_PARABOLICSTRUCTS_HPP #include "driver_structs.hpp" namespace specmicp { namespace dfpmsolver { enum class ParabolicLinesearch { Bactracking, // Bactracking linesearch Strang // Strang Linesearch }; enum class ParabolicLinesearchReturnCode { NotSupposedToHappen, MaximumIterations, LambdaTooSmall, Divergence, Success }; //! \brief Options of a parabolic driver //! struct ParabolicDriverOptions: public DriverOptions { scalar_t alpha; //!< Implicit/Cranck-Nicholson parameter ParabolicLinesearch linesearch; //!< The linesearch to use int quasi_newton; //!< Number of iterations without reforming the jacobian ParabolicDriverOptions(): DriverOptions(), alpha(1.0), linesearch(ParabolicLinesearch::Bactracking), quasi_newton(1) {} }; //! \brief Return codes enum class ParabolicDriverReturnCode { LinesearchFailed = -5, //!< Linesearch has failed (usually indicates a bad system) MaxIterations = -4, //!< Maximum number of iterations reached MaxStepTakenTooManyTimes = -3, //!< Maximum step taken too many times (divergence) ErrorLinearSystem = -2, //!< Error when solving the linear system StationaryPoint = -1, //!< Stationnary points are detected NotConvergedYet = 0, //!< Problem is not converged ResidualMinimized = 1, //!< The residual is minimized (Success) ErrorMinimized = 2 //!< Error is minimized (may be good) }; //! \brief Performance of the parabolic driver struct ParabolicDriverPerformance: public DriverPerformance { ParabolicDriverReturnCode return_code; ParabolicDriverPerformance(): DriverPerformance(), return_code(ParabolicDriverReturnCode::NotConvergedYet) {} }; } // end namespace dfpmsolver } // end namespace specmicp #endif // SPECMICP_DFPMSOLVER_PARABOLICSTRUCTS_HPP diff --git a/src/micpsolver/estimate_cond_number.hpp b/src/micpsolver/estimate_cond_number.hpp index 00356be..0cd19b4 100644 --- a/src/micpsolver/estimate_cond_number.hpp +++ b/src/micpsolver/estimate_cond_number.hpp @@ -1,114 +1,117 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_MICPSOLVER_ESTIMATECONDNUMBER_HPP #define SPECMICP_MICPSOLVER_ESTIMATECONDNUMBER_HPP #include //! \file estimate_cond_number.hpp Estimate the condition number of a matrix namespace specmicp { //! \namespace micpsolver Namespace for the MiCP Solver namespace micpsolver { //! \brief Estimate the condition number of a dense square triangular matrix //! //! References : //! - \cite Cline1979 //! - \cite Hager1984 //! //! @param tmatrix a triangular view of a dense matrix //! @param maxit maximum number of iterations done by the algorithm (2 triangular solve by iteration) //! template double estimate_condition_number(Eigen::TriangularView tmatrix, int maxit=10) { const int n = tmatrix.cols(); Eigen::VectorXd x = 1/n*Eigen::VectorXd::Ones(n); Eigen::VectorXd y(n); int cnt = 0; y = tmatrix.solve(x); while (cnt < maxit) { for (int i=0; i= 0) y(i) = 1; else y(i) = -1; } tmatrix.solveInPlace(y); y.reverseInPlace(); // transpose int j; const double maxi = y.array().abs().maxCoeff(&j); const double gamma = y.dot(x); if (maxi <= gamma) break; // This is a local maximum x= Eigen::VectorXd::Zero(n); x(j) = 1; y = tmatrix.solve(x); ++cnt; } // norm tmatrix // ------------ double nnorm; if (mode == Eigen::Lower) { nnorm = std::abs(tmatrix(0, 0)); for (int i=1; i-1; --i) { double normrow = 0; for (int j=i; j(); } } // end namespace micpsolver } // end namespace specmicp #endif // SPECMICP_MICPSOLVER_ESTIMATECONDNUMBER_HPP diff --git a/src/micpsolver/micpprog.hpp b/src/micpsolver/micpprog.hpp index adb5033..88f28f7 100644 --- a/src/micpsolver/micpprog.hpp +++ b/src/micpsolver/micpprog.hpp @@ -1,109 +1,112 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_MICPSOLVER_MICPPROG_HPP #define SPECMICP_MICPSOLVER_MICPPROG_HPP #include "common.hpp" //! \file micpprog.hpp The static interface of a MiCP solver namespace specmicp { namespace micpsolver { //! \class MiCPProg //! \brief A base clase for a MiCP program //! //! This class described a static interface. //! Any MiCP program should derived from this class and implement its methods template class MiCPProg { public: //! \brief Return the derived class Derived& derived() {return static_cast(*this);} //! \brief Return the number of variables //! //! Sould be implemented by the program index_t total_variables() {return derived->total_variables();} //! \brief Return the number of free variables //! //! Sould be implemented by the variables //! //! The free variables are the variables not subjected to the complementarity condition. index_t nb_free_variables() {return derived->total_variables();} //! \brief Return the number of constrained variables //! //! Not need to implemented this method by the program. index_t nb_complementarity_variables() {return total_variables() - nb_free_variables();} //! \brief Return the residuals //! //! \param[in] x the variables //! \param[out] residual the residuals void get_residuals(const Vector& x, Vector& residual); //! \brief Return the jacobian //! //! \param[in] x the variables //! \param[out] jacobian the jacobian void get_jacobian(Vector& x, Matrix& jacobian); //! \brief Called at the beginning of an iteration //! //! \param x the variables //! \param norm_residual norm of the residuals of the previous iteration //! \return A boolean indicating if the system can have converged //! //! Return true by default bool hook_start_iteration(const Vector& x, scalar_t norm_residual) {return true;} //! \brief Return the maximum update length that the algorithm can take //! //! This is usually used to impose nonnegativity conditions //! //! \param x the variables //! \param update solution of the linear system //! \return multiplicating factor to scale the update scalar_t max_lambda(const Vector& x, const Vector& update) {return 1.0;} //! \brief Return the value used for infinity static double infinity() {return HUGE_VAL;} }; } // end namespace micpsolver } // end namespace specmicp #endif // SPECMICP_MICPSOLVER_MICPPROG_HPP diff --git a/src/micpsolver/micpsolver.hpp b/src/micpsolver/micpsolver.hpp index a7a3e53..a55c161 100644 --- a/src/micpsolver/micpsolver.hpp +++ b/src/micpsolver/micpsolver.hpp @@ -1,210 +1,214 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ + #ifndef SPECMIC_MICPSOLVER_MICPSOLVER_HPP #define SPECMIC_MICPSOLVER_MICPSOLVER_HPP #include "common.hpp" #include "micpsolver_base.hpp" #include "ncp_function.hpp" //! \file micpsolver.hpp The MiCP solver namespace specmicp { namespace micpsolver { //! \class MiCPSolver //! \brief The MiCP Solver //! //! Solve //! - \f$ G(u, v) = 0\f$ //! - \f$ 0 \leq v \perp H(u,v) \geq 0 \f$ //! //! \tparam program_t a subclass of MiCPProg //! //! References : //! - \cite Munson2001 //! - \cite Facchinei2003 //! template class MiCPSolver: public MiCPSolverBaseProgram { public: using base = MiCPSolverBaseProgram; using base::get_options; using base::get_program; using base::get_perfs; using base::get_neq; using base::get_neq_free; //! \brief Constructor //! //! \param prog smart pointer toward an instance of a program_t to solve MiCPSolver(std::shared_ptr prog): MiCPSolverBaseProgram(prog), m_residuals(prog->total_variables()), m_phi_residuals(Vector::Zero(prog->total_variables())), m_jacobian(prog->total_variables(),prog ->total_variables()) {} // Merit function // ############## // Residuals and jacobian // ---------------------- //! \brief Compute the residuals, use internal storage //! //! \param[in] x the variables void compute_residuals(const Vector& x) { base::compute_residuals(x, m_residuals); } //! \brief Compute the jacobian //! //! Assumes that the residual have been computed before //! //! \param[in] x the variables void compute_jacobian(Vector& x) { base::compute_jacobian(x, m_jacobian); } //! \brief Reformulation of the residuals //! //! Reformulate the problem - assumes that r, the residual, has been computed before //! //! \param[in] x the variables //! \param[in] r the residuals //! \param[out] r_phi a vector of size neq, which will contain the reformulated residuals void reformulate_residuals(const Vector& x, const Vector& r, Vector& r_phi); //! \brief Reformulation of the residuals *inplace* //! //! \param[in] x the variables //! \param[in,out] r the residual, will contain the reformulated residuals void reformulate_residuals_inplace(const Vector &x, Vector &r); //! \brief Reformulation of the jacobian //! //! r is the original vector of residuals (not reformulated) void reformulate_jacobian(const Vector& x) { base::reformulate_jacobian_cck(x, m_residuals, m_jacobian); } // Algorithm // ######### //! \brief Solver the program using x as initial guess //! //! \param[in,out] x the initial guess, as output contains the solution (from the last iteration) MiCPSolverReturnCode solve(Vector& x); //! \brief Setup the residuals //! //! \param[in] x the current solution void setup_residuals(const Eigen::VectorXd& x) { compute_residuals(x); reformulate_residuals(x, m_residuals, m_phi_residuals); } //! \brief Setup the jacobian //! //! \param[in] x the current solution void setup_jacobian(Eigen::VectorXd& x) { compute_jacobian(x); reformulate_jacobian(x); m_grad_phi = m_jacobian.transpose() * m_phi_residuals; } //! \brief Solve the Newton system //! //! The system will be scaled before being solved, may be expensive and not necessary. //! Do disable the scaling, disable the corresponding options in #MiCPSolverOptions. //! It assumes that the Newton system has been formed //! //! \param[out] update the update to apply to the solution //! //! \sa search_direction_calculation_no_scaling. MiCPSolverReturnCode search_direction_calculation(Vector& update); //! \brief Solve the Newton system - does not scale the jacobian //! //! The system will not be scaled. //! It assumes that the Newton system has been formed //! //! \param[out] update the update to apply to the solution //! //! \sa search_direction_scaling MiCPSolverReturnCode search_direction_calculation_no_scaling(Vector &update); //! \brief Linesearch //! //! It is a backtracking linesearch. //! If the correct option is set, this is a nonmonotone linesearch. //! //! \param[in] x the current solution //! //! References : //! - \cite Dennis1983 //! - \cite Munson2001 //! //! \sa #MiCPSolverOptions int linesearch(Eigen::VectorXd& update, Eigen::VectorXd& x); //! \brief Crashing //! //! This function improves, if possible, the initial guess //! //! \param[in] x the current solution //! //! Reference : //! - \cite Munson2001 void crashing(Vector &x); private: // Residuals and jacobian Eigen::VectorXd m_residuals; //!< The residuals Eigen::VectorXd m_phi_residuals; //!< The reformulated residuals Eigen::VectorXd m_grad_phi; //!< The gradient of the reformulated residuals Eigen::MatrixXd m_jacobian; //!< The jacobian std::vector m_max_merits; //!< Contains the m best value of the merit function bool m_gradient_step_taken; //!< True if the update was computed using the gradient }; } // end namespace micpsolver } // end namespace specmicp // ###############// // Implementation // // ###############// #include "micpsolver.inl" #endif // SPECMIC_MICPSOLVER_MICPSOLVER_HPP diff --git a/src/micpsolver/micpsolver.inl b/src/micpsolver/micpsolver.inl index fc671b7..c21d5f2 100644 --- a/src/micpsolver/micpsolver.inl +++ b/src/micpsolver/micpsolver.inl @@ -1,445 +1,448 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMIC_MICPSOLVER_MICPSOLVER_HPP #include "micpsolver.hpp" // for syntaxic coloration... #endif // SPECMIC_MICPSOLVER_MICPSOLVER_HPP #include #include "estimate_cond_number.hpp" #include "utils/log.hpp" //! \file micpsolver.inl implementation of the MiCP solver namespace specmicp { namespace micpsolver { // Main algorithm // ############## template MiCPSolverReturnCode MiCPSolver::solve(Vector &x) { int cnt = 0; if (get_options().use_crashing) crashing(x); else setup_residuals(x); MiCPSolverReturnCode retcode = MiCPSolverReturnCode::NotConvergedYet; Eigen::VectorXd update(get_neq()); while (retcode == MiCPSolverReturnCode::NotConvergedYet) { DEBUG << "Iteration : " << cnt; // (S.0) Initialization of the iteration // this is a hook for simultaneous fixed-point iterations // implemented to solve the non-ideality model bool may_have_converged = get_program()->hook_start_iteration(x, m_phi_residuals.norm()); // (S.1) Check the convergence setup_residuals(x); get_perfs().current_residual = m_phi_residuals.norm(); DEBUG << "Norm residuals : " << get_perfs().current_residual; retcode = base::check_convergence(cnt, update, x, m_phi_residuals, may_have_converged); get_perfs().return_code = retcode; if (retcode != MiCPSolverReturnCode::NotConvergedYet) break; ++cnt; // (S.2) Compute the jacobian and solve the linear problem setup_jacobian(x); if(get_options().use_scaling) search_direction_calculation(update); else search_direction_calculation_no_scaling(update); // (S.3) Linesearch int termcode = linesearch(update, x); if (termcode != 0) retcode = MiCPSolverReturnCode::LinesearchFailure; get_perfs().return_code = retcode; get_perfs().current_update = update.norm(); DEBUG << "Return LineSearch : " << termcode; base::projection(x); // project x to the positive quadrant get_perfs().nb_iterations = cnt; } return retcode; } template MiCPSolverReturnCode MiCPSolver::search_direction_calculation(Eigen::VectorXd& update) { Vector rscaler(Vector::Ones(m_jacobian.cols())); Vector cscaler(Vector::Ones(m_jacobian.rows())); base::scaling_jacobian(m_jacobian, m_phi_residuals, rscaler, cscaler); m_jacobian = rscaler.asDiagonal() * (m_jacobian) * cscaler.asDiagonal(); Eigen::ColPivHouseholderQR solver(m_jacobian.rows(), m_jacobian.cols()); // it needs to be correctly initialized m_gradient_step_taken = false; int m; for (m=0; m 0) { scalar_t cond = estimate_condition_number(solver.matrixR().triangularView()); if (cond > get_options().condition_limit) { m_gradient_step_taken = true; m_jacobian.diagonal() += lambda*rscaler.cwiseProduct(cscaler); continue; } } update = solver.solve(-rscaler.cwiseProduct(m_phi_residuals + m*lambda*m_grad_phi)); update = cscaler.cwiseProduct(update); if (get_options().factor_descent_condition < 0 ) break; // we have a solution // else we compute the descent condition scalar_t descent_cond = m_grad_phi.dot(update); scalar_t norm_grad = m_grad_phi.norm(); scalar_t norm_update = update.norm(); if ((descent_cond <= -get_options().factor_descent_condition*std::min( std::pow(norm_update,2),std::pow(norm_update,3))) and (descent_cond <= -get_options().factor_descent_condition*std::min( std::pow(norm_grad,2),std::pow(norm_grad,3))) ) break; // we have a solution ! m_gradient_step_taken = true; m_jacobian.diagonal() += lambda*rscaler.cwiseProduct(cscaler); } DEBUG << "Gradient step : m = " << m; if (m == get_options().max_factorization_step) { INFO << "Full gradient step taken !"; update = -m_grad_phi; } return MiCPSolverReturnCode::NotConvergedYet; } template MiCPSolverReturnCode MiCPSolver::search_direction_calculation_no_scaling( Vector& update ) { Eigen::ColPivHouseholderQR solver(m_jacobian.rows(), m_jacobian.cols()); // it needs to be correctly initialized // if everything is ok, this is the only decomposition m_gradient_step_taken = false; int m; // this is an index that increase the contribution of the gradient in the solution // the pure Newton solution is when m=0 for (m=0; m 0) { scalar_t cond = estimate_condition_number(solver.matrixR().triangularView()); if (cond > get_options().condition_limit) { // add the perturbation m_gradient_step_taken = true; m_jacobian.diagonal() += Eigen::VectorXd::Constant(m_jacobian.rows(), lambda); } } update = solver.solve(-(m_phi_residuals + m*lambda*m_grad_phi)); if (get_options().factor_descent_condition < 0 ) break; // we have a solution scalar_t descent_cond = m_grad_phi.dot(update); scalar_t norm_grad = m_grad_phi.norm(); scalar_t norm_update = update.norm(); if ( (descent_cond <= -get_options().factor_descent_condition*std::min( std::pow(norm_update,2),std::pow(norm_update,3))) and (descent_cond <= -get_options().factor_descent_condition*std::min( std::pow(norm_grad,2),std::pow(norm_grad,3))) ) break; // we have a solution ! // add the perturbation m_gradient_step_taken = true; m_jacobian.diagonal() += Eigen::VectorXd::Constant(m_jacobian.rows(), lambda); } DEBUG << "Gradient step : m = " << m; if (m_gradient_step_taken && m == get_options().max_factorization_step) { INFO << "Full gradient step taken !"; update = -m_grad_phi; } return MiCPSolverReturnCode::NotConvergedYet; } template void MiCPSolver::crashing(Vector& x) { // steepest descent direction algorithm DEBUG << "Crashing "; const scalar_t beta = 0.5; const scalar_t sigma = 1e-5; int cnt = 0; while (cnt < 10) { setup_residuals(x); setup_jacobian(x); m_grad_phi = m_jacobian.transpose()*m_phi_residuals; Vector xp(get_neq()); int l=0; const int maxl = 10; while (l void MiCPSolver::reformulate_residuals( const Vector &x, const Vector &r, Vector &r_phi ) { // reformulation with copy from r to r_phi r_phi.resizeLike(r); r_phi.block(0, 0, get_neq_free(), 1) = r.block(0, 0, get_neq_free(), 1); for (index_t i = get_neq_free(); i void MiCPSolver::reformulate_residuals_inplace( const Vector& x, Vector& r ) { for (index_t i = get_neq_free(); i int MiCPSolver::linesearch(Eigen::VectorXd& p, Eigen::VectorXd& x) { // References // ---------- // - Algo A6.3.1 : Dennis and Schnabel (1983) // - Munson et al. (2001) // - Facchinei (2003) // - Nocedal & Wrigth (2006) DEBUG << "Linesearch"; Eigen::VectorXd xp(get_neq()); Eigen::VectorXd new_res(get_neq()); double fcp; get_perfs().max_taken = false; int retcode = 2; const double alpha = 1e-4; double newtlen = base::is_step_too_long(p); double init_slope = m_grad_phi.dot(p); double rellength = std::abs(p(0)); for (int i=1; imax_lambda(x, p); double lambda_prev = lambda; // non monotone linesearch // ======================= double merit_value = 0.5*m_phi_residuals.squaredNorm(); // new residual xp = x + lambda*p; base::compute_residuals(xp, new_res); reformulate_residuals_inplace(xp, new_res); fcp = 0.5*new_res.squaredNorm(); // Skip linesearch if enough progress is done // ------------------------------------------ if (fcp < get_options().coeff_accept_newton_step *merit_value) { if (m_max_merits.size() > 0) m_max_merits[m_max_merits.size()-1] = merit_value; else m_max_merits.push_back(merit_value); x = xp; return 0; } // Select the merit value of reference // ----------------------------------- if (get_options().non_monotone_linesearch) { double mmax = merit_value; if (m_max_merits.size() > 0) { mmax = m_max_merits[m_max_merits.size()-1]; // check for cycling // - - - - - - - - - if ( m_max_merits.size() ==4 && std::fabs(mmax - merit_value) < get_options().threshold_cycling_linesearch*get_options().fvectol) { //std::cout << merit_value << std::endl; WARNING << "Cycling has been detected by the linesearch - Taking the full Newton step"; x = xp; p = lambda*p; return 3; } } if (m_max_merits.size() < 4) { m_max_merits.push_back(merit_value); if (merit_value < mmax) merit_value = (3*merit_value + mmax)/4; } else if (merit_value < mmax) { m_max_merits[3] = merit_value; merit_value = mmax; } if (m_gradient_step_taken) { merit_value *= 100; } } // The linesearch // -------------- double fc = merit_value; double fcp_prev; int cnt = 0; do { fcp = 0.5*new_res.squaredNorm(); if (fcp <= fc - std::min(-alpha*lambda*init_slope,(1-alpha)*fc)) //pg760 Fachinei2003 { retcode = 0; if (lambda ==1 and (newtlen > 0.99 * get_options().maxstep)) { get_perfs().max_taken = true; } break; } else if (lambda < minlambda) { ERROR << "Linesearch cannot find a solution bigger than the minimal step"; retcode = 1; break; } else { // Select a new step length // - - - - - - - - - - - - double lambdatmp; if (cnt == 0) { // only a quadratic at the first lambdatmp = - init_slope / (2*(fcp - fc -init_slope)); } else { const double factor = 1 /(lambda - lambda_prev); const double x1 = fcp - fc - lambda*init_slope; const double x2 = fcp_prev - fc - lambda_prev*init_slope; const double a = factor * ( x1/(lambda*lambda) - x2/(lambda_prev*lambda_prev)); const double b = factor * ( -x1*lambda_prev/(lambda*lambda) + x2*lambda/(lambda_prev*lambda_prev)); if (a == 0) { // cubic interpolation is in fact a quadratic interpolation lambdatmp = - init_slope/(2*b); } else { const double disc = b*b-3*a*init_slope; lambdatmp = (-b+std::sqrt(disc))/(3*a); } if (lambdatmp > 0.5*lambda ) lambdatmp = 0.5*lambda; } lambda_prev = lambda; fcp_prev = fcp; if (lambdatmp < 0.1*lambda) { lambda = 0.1 * lambda; } else { lambda = lambdatmp; } if (not std::isfinite(lambda)) { ERROR << "Lambda is non finite in micpsolver linesearch - we stop"; return 3; } } xp = x + lambda*p; base::compute_residuals(xp, new_res); reformulate_residuals_inplace(xp, new_res); ++cnt; } while(retcode == 2 and cnt < 100); DEBUG << "Lambda : " << lambda; if (cnt == 100) { ERROR << "Too much linesearch iterations ! We stop"; } x = xp; p = lambda*p; return retcode; } } // end namespace micpsolver } // end namespace specmicp diff --git a/src/micpsolver/micpsolver_base.hpp b/src/micpsolver/micpsolver_base.hpp index 27c1bc8..5067707 100644 --- a/src/micpsolver/micpsolver_base.hpp +++ b/src/micpsolver/micpsolver_base.hpp @@ -1,185 +1,189 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ + #ifndef SPECMICP_MICPSOLVER_MICPSOLVERBASE_HPP #define SPECMICP_MICPSOLVER_MICPSOLVERBASE_HPP //! \file micpsolver_base.hpp Base class for micpsolver #include #include "common.hpp" #include "micpsolver_structs.hpp" #include "utils/log.hpp" #include "utils/options_handler.hpp" #include "utils/perfs_handler.hpp" namespace specmicp { namespace micpsolver { //! \brief Base class for an MiCP solver //! //! Handle the program, options and performance //! template class MiCPSolverBaseProgram: public OptionsHandler, public PerformanceHandler { public: using program_ptr = std::shared_ptr; using OptionsHandler::get_options; using PerformanceHandler::get_perfs; MiCPSolverBaseProgram(): OptionsHandler(), PerformanceHandler() {} //! \brief Constructor //! //! \param prog shared_ptr to the program MiCPSolverBaseProgram(program_ptr prog): OptionsHandler(), PerformanceHandler(), m_program(prog) {} //! \brief Return the program //! //! This is due to the templating, allow to do get_program()->whatever(); program_ptr& get_program() {return m_program;} //! \brief Return the number of equations index_t get_neq() const {return m_program->total_variables();} //! \brief Return the number of equations corresponding to the free variables (size of G) index_t get_neq_free() const {return m_program->nb_free_variables();} //! \brief Compute the residuals, store it in r //! //! \param[in] x the variables //! \param[out] r vector to store the residuals (must be of the same size as x) void compute_residuals(const Vector& x, Vector& r) { m_program->get_residuals(x, r); get_perfs().nb_call_residuals += 1; } //! \brief Compute the jacobian //! //! Assumes that the residual have been computed before //! //! \param[in] x the variables //! \param[out] jacobian the jacobian void compute_jacobian(Vector& x, Matrix& jacobian) { m_program->get_jacobian(x, jacobian); get_perfs().nb_call_jacobian += 1; } //! \brief Compute the factors to scale the jacobian //! //! \param[in] jacobian the jacobian to scale (from the reformulated problem) //! \param[in] residuals the residuals corresponding to the jacobian //! \param[out] rscaler scaling factors of the rows //! \param[out] cscaler scaling factors of the columns void scaling_jacobian( const Matrix& jacobian, const Vector& residuals, Vector& rscaler, Vector& cscaler); //! \brief Check for convergence //! //! \param nb_iterations the number of iterations //! \param update the update taken at the previous iteration //! \param solution the current solution //! \param residuals current residuals //! \param may_have_converged a boolean given by the user to indicates if the problem has converged yet //! \return a MiCPSolverReturnCode describing the state of the algorithm MiCPSolverReturnCode check_convergence(int nb_iterations, const Vector& update, const Vector& solution, const Vector &residuals, bool may_have_converged = true); //! \brief Reformulate the jacobian using the cck function //! //! \param x the variables //! \param r the residuals //! \param jacobian the jacobian void reformulate_jacobian_cck( const Vector& x, const Vector& r, Matrix& jacobian ); //! \brief Compute the norm of the update //! //! \tparam p order of the norm (1, 2, ..., Eigen::Infinity) //! \param update the solution of the linear system //! \param solution the solution (variables) template double norm_update(const Vector& update, const Vector& solution) const { return (update.array().abs()/(solution.array().max(1)) ).matrix().template lpNorm

(); } //! \brief Project variables on the feasible set //! //! \param x the variables void projection(Vector& x); //! \brief Return the step corrected step length if it is too long //! //! \param update the solution of the linear system scalar_t is_step_too_long(Vector& update); protected: //! \brief Set the program //! //! \param program_ptr shared_ptr to the program program_ptr& set_program(program_ptr theprogram) { m_program = theprogram; } private: program_ptr m_program; }; } // end namespace micpsolver } // end namespace specmicp // ----------------------------------- // // Implementation // // ----------------------------------- // #include "micpsolver_base.inl" #endif // SPECMICP_MICPSOLVER_MICPSOLVERBASE_HPP diff --git a/src/micpsolver/micpsolver_base.inl b/src/micpsolver/micpsolver_base.inl index 055b7e9..3e6912e 100644 --- a/src/micpsolver/micpsolver_base.inl +++ b/src/micpsolver/micpsolver_base.inl @@ -1,184 +1,188 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ + #include "micpsolver_base.hpp" // syntaxic coloration namespace specmicp { namespace micpsolver { // ref : Munson et al. (2001) template void MiCPSolverBaseProgram::scaling_jacobian( const Matrix& jacobian, const Vector& residuals, Vector& rscaler, Vector& cscaler) { for (int i=0; i MiCPSolverReturnCode MiCPSolverBaseProgram::check_convergence( int nb_iterations, const Vector& update, const Vector& solution, const Vector& residuals, bool may_have_converged ) { MiCPSolverReturnCode termcode = MiCPSolverReturnCode::NotConvergedYet; const scalar_t norm_residuals = residuals.lpNorm(); if (norm_residuals < get_options().fvectol) { if (may_have_converged == true) termcode = MiCPSolverReturnCode::ResidualMinimized; } else if (nb_iterations >0 and norm_update(update, solution) < get_options().steptol) { if (norm_residuals > get_options().threshold_stationary_point) { ERROR << "Stationary point detected !"; termcode = MiCPSolverReturnCode::StationaryPoint; } if (may_have_converged == true) { WARNING << "MiCP solver : Error is minimized - may indicate a stationnary point"; termcode = MiCPSolverReturnCode::ErrorMinimized; } } else if (nb_iterations > get_options().max_iter) { ERROR << "Maximum number of iteration reached (" << get_options().max_iter << ")"; termcode = MiCPSolverReturnCode::MaxIterations; } else if (get_perfs().max_taken) { ++get_perfs().nb_consecutive_max_taken; ++get_perfs().nb_max_taken; if (get_perfs().nb_consecutive_max_taken == get_options().maxiter_maxstep) { ERROR << "Divergence detected - Maximum step length taken two many times"; termcode = MiCPSolverReturnCode::MaxStepTakenTooManyTimes; } } else { get_perfs().nb_consecutive_max_taken = 0; } return termcode; } template void MiCPSolverBaseProgram::reformulate_jacobian_cck( const Vector& x, const Vector& r, Matrix& jacobian ) { // set the z vector : contains 1 for degenerate points Eigen::VectorXd z(Eigen::VectorXd::Zero(get_neq())); for (index_t i=get_neq_free(); i 0) and (x(i) >0)) { c -= (1-lambda)*r(i); d -= (1-lambda)*x(i); } jacobian.row(i) *= d; jacobian(i, i) += c; } } } // Projection of the variables onto the feasible set template void MiCPSolverBaseProgram::projection(Vector& x) { for (index_t i=0; inb_complementarity_variables(); ++i) { if (x(i+get_program()->nb_free_variables()) < get_options().projection_min_variable) { x(i+get_program()->nb_free_variables()) = 0; } } } template scalar_t MiCPSolverBaseProgram::is_step_too_long(Vector& update) { scalar_t steplength = update.norm(); if (steplength > get_options().maxstep) { get_perfs().max_taken = true; update = get_options().maxstep / steplength * update; steplength = get_options().maxstep; } return steplength; } } // end namespace micpsolver } // end namespace specmicp diff --git a/src/micpsolver/micpsolver_min.hpp b/src/micpsolver/micpsolver_min.hpp index c41659d..f836d4d 100644 --- a/src/micpsolver/micpsolver_min.hpp +++ b/src/micpsolver/micpsolver_min.hpp @@ -1,121 +1,124 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_MICPSOLVER_MICPSOLVERMIN_HPP #define SPECMICP_MICPSOLVER_MICPSOLVERMIN_HPP //! \file micpsolver_min.hpp micpsolver based on the min function #include "micpsolver_base.hpp" namespace specmicp { namespace micpsolver { //! \brief MiCP solver using the min function template class MiCPSolverMin: public MiCPSolverBaseProgram { public: using base = MiCPSolverBaseProgram; using MiCPSolverBaseProgram::get_options; using MiCPSolverBaseProgram::get_program; using MiCPSolverBaseProgram::get_perf; using MiCPSolverBaseProgram::get_neq; using MiCPSolverBaseProgram::get_neq_free; //! \brief Constructor //! //! @param prog smart pointer toward an instance of a Program to solve MiCPSolverMin(std::shared_ptr prog): MiCPSolverBaseProgram(prog), m_residuals(prog->total_variables()), m_grad_phicck(prog->total_variables()), m_jacobian(prog->total_variables(),prog ->total_variables()) { m_max_merits.reserve(4); } //! \brief Solve the program //! //! @param[in,out] x (in) initial guess, (out) solution MiCPSolverReturnCode solve(Eigen::VectorXd& x); MiCPSolverReturnCode search_direction_calculation(Eigen::VectorXd& x, Eigen::VectorXd& update); int linesearch(Eigen::VectorXd& p, Eigen::VectorXd& x); //! \brief Setup the residuals //! //! @param[in] x the current solution void setup_residuals(const Eigen::VectorXd& x) { base::compute_residuals(x, m_residuals); } void setup_jacobian(Eigen::VectorXd& x) { base::compute_jacobian(x, m_jacobian); } //! Reduce the system //! //! @return reduced number of freedom int reduce_system(const Eigen::VectorXd& x, Eigen::MatrixXd& reduced_jacobian, Eigen::VectorXd& reduced_residual); void reformulate_residuals_cck_inplace(const Eigen::VectorXd& x, Eigen::VectorXd& residuals); void reformulate_result(const Eigen::VectorXd &x, Eigen::VectorXd &update); private: void sanitize(Eigen::VectorXd &x); Eigen::VectorXd m_residuals; Eigen::VectorXd m_grad_phicck; Eigen::MatrixXd m_jacobian; bool m_gradient_step_taken; std::vector m_max_merits; //!< Contains the m best value of the merit function double m_newton_length; }; } // end namespace micpsolver } // end namespace specm // implementation // -------------- #include "micpsolver_min.inl" #endif // SPECMICP_MICPSOLVER_MICPSOLVERMIN_HPP diff --git a/src/micpsolver/micpsolver_min.inl b/src/micpsolver/micpsolver_min.inl index 185d8f4..f6a63eb 100644 --- a/src/micpsolver/micpsolver_min.inl +++ b/src/micpsolver/micpsolver_min.inl @@ -1,379 +1,383 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ + #include "micpsolver_min.hpp" // for syntaxic coloration #include "utils/log.hpp" #include "ncp_function.hpp" #include "estimate_cond_number.hpp" namespace specmicp { namespace micpsolver { template MiCPSolverReturnCode MiCPSolverMin::solve(Eigen::VectorXd& x) { int cnt = 0; MiCPSolverReturnCode retcode = MiCPSolverReturnCode::NotConvergedYet; Eigen::VectorXd update(Eigen::VectorXd::Zero(get_neq())); setup_residuals(x); while (retcode == MiCPSolverReturnCode::NotConvergedYet) { DEBUG << "Iteration : " << cnt; DEBUG << "Solution : \n" << x; get_program()->hook_start_iteration(x, m_residuals.norm()); setup_residuals(x); get_perf().current_residual = m_residuals.norm(); SPAM << "Residuals : \n ----- \n" << m_residuals << "\n ----- \n"; retcode = base::check_convergence(cnt, update, x, m_residuals); get_perf().return_code = retcode; if (retcode != MiCPSolverReturnCode::NotConvergedYet) break; ++cnt; get_perf().max_taken = false; setup_jacobian(x); search_direction_calculation(x, update); sanitize(x); int termcode = linesearch(update, x); get_perf().current_update = update.norm(); DEBUG << "Return LineSearch : " << termcode; base::projection(x); get_perf().nb_iterations = cnt; } return retcode; } template MiCPSolverReturnCode MiCPSolverMin::search_direction_calculation( Eigen::VectorXd& x, Eigen::VectorXd& update) { Eigen::MatrixXd reduced_jacobian; Eigen::VectorXd reduced_residual; reduce_system(x, reduced_jacobian, reduced_residual); DEBUG << reduced_jacobian; Eigen::ColPivHouseholderQR solver; m_gradient_step_taken = false; solver.compute(reduced_jacobian); get_perf().nb_factorization += 1; { // first condition : is the factorization ok ? if (solver.info() != Eigen::Success or not solver.isInvertible()) { DEBUG << "Solver.info : " << solver.info() << " - is invertible : " << solver.isInvertible(); m_gradient_step_taken = true; goto after_second_cond; // jump directly to the gradient step } } { // second condition : is the condition number ok ? const double cond = estimate_condition_number(solver.matrixR().triangularView()); DEBUG << "Condition number : " << cond; if (cond > get_options().condition_limit) { m_gradient_step_taken = true; } } after_second_cond: // third condition : is the descent condition respected update = solver.solve(-reduced_residual); m_grad_phicck = reduced_jacobian.transpose()*reduced_residual; const double descent_cond = m_grad_phicck.dot(update); reformulate_result(x, update); base::reformulate_jacobian_cck(x, m_residuals, m_jacobian); reformulate_residuals_cck_inplace(x, m_residuals); m_grad_phicck = m_jacobian.transpose()*m_residuals; m_grad_phicck(0) = 0; if (not m_gradient_step_taken) { m_newton_length = base::is_step_too_long(update); // we compute the descent condition //const double descent_cond = m_grad_phicck.dot(update); const double norm_update = update.norm(); DEBUG << "grad(phi).dot(update) = " << descent_cond << " compared to : " << ( - get_options().factor_descent_condition * std::pow(norm_update, get_options().power_descent_condition)); if (descent_cond > - get_options().factor_descent_condition * std::pow(norm_update, get_options().power_descent_condition)) { m_gradient_step_taken = true; } } if (m_gradient_step_taken) { INFO << "Full gradient step taken !"; update = - m_grad_phicck; m_newton_length = base::is_step_too_long(update); } return MiCPSolverReturnCode::NotConvergedYet; } template int MiCPSolverMin::reduce_system(const Eigen::VectorXd& x, Eigen::MatrixXd& reduced_jacobian, Eigen::VectorXd& reduced_residual) { reduced_jacobian.resizeLike(m_jacobian); // memory is cheap, we will resize at the end reduced_jacobian.setZero(); reduced_residual.resizeLike(m_residuals); // copy identical information int ideq_reduced = get_neq_free(); reduced_jacobian.block(0, 0, get_neq_free(), get_neq_free()) = m_jacobian.block(0, 0, get_neq_free(), get_neq_free()); // select active degree of freedom Eigen::VectorXd to_remove(get_neq()-get_neq_free()); for (int dof=get_neq_free(); dof= m_residuals(dof)) { DEBUG << "Mineral to precipitate : " << dof; reduced_residual(ideq_reduced) = m_residuals(dof); reduced_jacobian.block(ideq_reduced, 0, 1, get_neq_free()) = m_jacobian.block(dof, 0, 1, get_neq_free()); reduced_jacobian.block(0, ideq_reduced, get_neq_free(), 1) = m_jacobian.block(0, dof, get_neq_free(), 1); to_remove(dof-get_neq_free()) = 0; ++ideq_reduced; } else { to_remove(dof-get_neq_free()) = x(dof); } } reduced_residual.block(0, 0, get_neq_free(), 1) -= m_jacobian.block(0, get_neq_free(), get_neq_free(), get_neq()-get_neq_free())*to_remove; reduced_jacobian.conservativeResize(ideq_reduced, ideq_reduced); reduced_residual.conservativeResize(ideq_reduced); DEBUG << "ideq reduced : " << ideq_reduced; return ideq_reduced; } template void MiCPSolverMin::reformulate_result(const Eigen::VectorXd& x, Eigen::VectorXd& update) { update.conservativeResizeLike(x); int tot_to_keep = 0; for (int dof=get_neq_free(); dof= m_residuals(dof)) ++tot_to_keep; } int kept_dof = 1; for (int dof=get_neq()-1; dof>=get_neq_free(); --dof) { // we go backwards to avoid extra copies if (x(dof) >= m_residuals(dof)) { update(dof) = update(get_neq_free()+(tot_to_keep-kept_dof)); ++kept_dof; } else { update(dof) = -x(dof); } } } template void MiCPSolverMin::sanitize(Eigen::VectorXd& x) { if (x(0) <=0) x(0) = 1; for (int dof=get_neq_free(); dof void MiCPSolverMin::reformulate_residuals_cck_inplace(const Eigen::VectorXd& x, Eigen::VectorXd& residuals) { for (int i = get_neq_free(); i int MiCPSolverMin::linesearch(Eigen::VectorXd& p, Eigen::VectorXd& x) { // Reference Algo A6.3.1 : Dennis and Schnabel (1983) DEBUG << "Linesearch"; Eigen::VectorXd xp(get_neq()); Eigen::VectorXd new_res(get_neq()); double fcp; get_perf().max_taken = false; int retcode = 2; const double alpha = get_options().factor_descent_condition; double newtlen = m_newton_length; //double newtlen = p.norm(); double init_slope = m_grad_phicck.dot(p); double rellength = std::abs(p(0)); for (int i=1; imax_lambda(x, p); DEBUG << "Initial lambda : " << lambda; double lambda_prev = lambda; // non monotone linesearch // // - reference : Munson et al. (2001) // ------------------------------------ double merit_value = 0.5*m_residuals.squaredNorm(); // // new residual //reformulate_result(x, p); xp = x + lambda*p; DEBUG << "update \n" << p < 0) m_max_merits[m_max_merits.size()-1] = merit_value; else m_max_merits.push_back(merit_value); x = xp; return 0; } DEBUG << "Merit value : " << merit_value; double mmax = merit_value; if (m_max_merits.size() > 0) { mmax = m_max_merits[m_max_merits.size()-1]; } if (m_max_merits.size() < 4) { m_max_merits.push_back(merit_value); if (merit_value < mmax) merit_value = (3*merit_value + mmax)/4; } else if (merit_value < mmax) { m_max_merits[3] = merit_value; merit_value = mmax; } if (m_gradient_step_taken) { merit_value *= 100; } DEBUG << "Merit value used : " << merit_value; double fc = merit_value; double fcp_prev; int cnt = 0; do { DEBUG << "cnt : " << cnt << " - lambda : " << lambda; DEBUG << "fcp : " << fcp << "\n fc+alin : " << fc+alpha*lambda*init_slope << " # fc : " << fc << std::endl; if (fcp <= fc + alpha*lambda*init_slope) { retcode = 0; if (lambda ==1 and (newtlen > 0.99 * get_options().maxstep)) { get_perf().max_taken = true; } break; } else if (lambda < minlambda) { lambda = get_program()->max_lambda(x, p); xp = x + lambda*p; retcode = 1; break; } else { double lambdatmp; if (cnt == 0) { // only a quadratic at the first lambdatmp = - init_slope / (2*(fcp - fc -init_slope)); } else { const double factor = 1 /(lambda - lambda_prev); const double x1 = fcp - fc - lambda*init_slope; const double x2 = fcp_prev - fc - lambda_prev*init_slope; const double a = factor * ( x1/(lambda*lambda) - x2/(lambda_prev*lambda_prev)); const double b = factor * ( -x1*lambda_prev/(lambda*lambda) + x2*lambda/(lambda_prev*lambda_prev)); if (a == 0) { // cubic interpolation is in fact a quadratic interpolation DEBUG << "not disc : " << - init_slope/(2*b); lambdatmp = - init_slope/(2*b); } else { const double disc = b*b-3*a*init_slope; lambdatmp = (-b+std::sqrt(disc))/(3*a); } if (lambdatmp > 0.5*lambda ) lambdatmp = 0.5*lambda; } DEBUG << "lambdatmp : " << lambdatmp; lambda_prev = lambda; fcp_prev = fcp; if (not std::isfinite(lambdatmp)) { lambda = get_program()->max_lambda(x, p); xp = x + lambda*p; retcode = 1; break; } else if ((lambdatmp < 0.1*lambda)) { lambda = 0.1 * lambda; } else { lambda = lambdatmp; } DEBUG << "lambda end : " << lambda; } xp = x + lambda*p; //sanitize(xp); DEBUG << "xp : " << std::endl << xp; base::compute_residuals(xp, new_res); reformulate_residuals_cck_inplace(xp, new_res); fcp = 0.5*new_res.squaredNorm(); ++cnt; } while(retcode == 2 and cnt < 100); DEBUG << "Lambda : " << lambda; if (cnt == 100) { ERROR << "Too much linesearch iterations ! We stop"; } x = xp; p = lambda*p; return retcode; } } // end namespace micpsolver } // end namespace specmicp diff --git a/src/micpsolver/micpsolver_structs.hpp b/src/micpsolver/micpsolver_structs.hpp index 1152e49..665f806 100644 --- a/src/micpsolver/micpsolver_structs.hpp +++ b/src/micpsolver/micpsolver_structs.hpp @@ -1,230 +1,233 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_MICPSOLVER_MICPSOLVERSTRUCTS_HPP #define SPECMICP_MICPSOLVER_MICPSOLVERSTRUCTS_HPP //! \file micpsolver_structs.hpp structures and enum used by the micpsolver // this file exists to reduce the header dependancy #include namespace specmicp { namespace micpsolver { //! \brief Options for the MiCPSolver struct MiCPSolverOptions { int max_iter; //!< Maximum number of iterations allowed // tolerances double fvectol; //!< Tolerance for minimization of residuals double steptol; //!< Tolerance for minimization of error // misc ... double condition_limit; //!< Condition number limit, -1 to disable it double penalization_factor; //!< Penalization factor for the penalized Fisher-Burmeister function double maxstep; //!< the maximum step allowed int maxiter_maxstep; //!< the maximum number of step of length maxstep allowed double factor_descent_condition; //!< factor in front of the descent condition > 0 double power_descent_condition; //!< power used in the traditional format of the descent condition > 2 bool use_crashing; //! Use a crashing step to improve the starting guess double coeff_accept_newton_step; //! Accept the newton step without line search if merit(x+d)threshold_stationary_point and ErrorMinimized -> stationary point double threshold_cycling_linesearch; //! factor to detect cycling in linesearch int max_factorization_step; //! Max number of factorization in an iteration bool non_monotone_linesearch; //! Use non monotone linesearch //! \brief Constructor - also defines the default value used by the algorithm MiCPSolverOptions(): max_iter(100), fvectol(1e-8), steptol(1e-10), condition_limit(1e6), penalization_factor(0.8), maxstep(100), // this is quite restrictif maxiter_maxstep(20), factor_descent_condition(1e-4), power_descent_condition(2), use_crashing(false), coeff_accept_newton_step(0.95), use_scaling(true), factor_gradient_search_direction(5.0), projection_min_variable(DBL_EPSILON), threshold_stationary_point(1e-6), threshold_cycling_linesearch(1e-5), max_factorization_step(4), non_monotone_linesearch(true) {} //! \brief Set the maximum number of iterations void set_maximum_iterations(int maximum_iterations) { max_iter = maximum_iterations; } //! \brief Set the maximum step length void set_maximum_step_length(double step_length) { maxstep = step_length; } //! \brief Set the maximum step length void set_maximum_step_length(double step_length, int max_iter_at_step_length) { maxstep = step_length; maxiter_maxstep = max_iter_at_step_length; } //! \brief Disable the descent condition void disable_descent_direction() { factor_descent_condition = -1.0; } //! \brief Enable the descent condition void enable_descent_direction(double factor, double power) { factor_descent_condition = factor; power_descent_condition = power; } //! \brief Disable the condition check void disable_condition_check() { condition_limit = -1; } //! \brief Enable the condition check void enable_condition_check(double threshold) { condition_limit = threshold; } //! \brief Disable the non-monotone linesearch void disable_non_monotone_linesearch() { non_monotone_linesearch = false; } //! \brief Enable the non-monotone linesearch void enable_non_monotone_linesearch() { non_monotone_linesearch = true; } //! \brief Enable the scaling void enable_scaling() { use_scaling = true; } //! \brief Disable the scaling void disable_scaling() { use_scaling = false; } //! \brief Enable the crashing void enable_crashing() { use_crashing = true; } //! \brief Disable the scaling void disable_crashing() { use_crashing = false; } //! \brief Set tolerance void set_tolerance(double residuals_tolerance) { fvectol = residuals_tolerance; } //! \brief Set tolerances void set_tolerance(double residuals_tolerance, double step_tolerance) { fvectol = residuals_tolerance; steptol = step_tolerance; } }; //! \brief Return code of the MiCP solver //! //! A positive return code means that the algorithm converged (but maybe to a stationnary points) //! A negative return code means that something wrong happened and was detected enum class MiCPSolverReturnCode { LolItsNotSupposedToHappen = -10, //!< bummer... LinesearchFailure = -5, //!< Failure in linesearch MaxStepTakenTooManyTimes = -4, //!< Probably detect a divergence FailedToSolveLinearSystem = -3, //!< Problem in the decomposition... shouldn't be raised, use of the gradient step MaxIterations = -2, //!< Algorithm has reached the maximum number of iterations StationaryPoint = -1, //!< Algorithm is stuck in a stationnary point of the merit function NotConvergedYet = 0, //!< Keep going... Success = 1, //!< Test success (well be careful of stationnary points) ResidualMinimized = 2, //!< The residual is minimized (i.e. close to zero) ErrorMinimized = 3 //!< The error is minimized, may indicate a stationary point }; //! \brief This structure contains counter to check/query the performance of the algorithm //! //! It should be updated after each operations, not at the end struct MiCPPerformance { int nb_call_residuals; //! Number of calls of the residual int nb_call_jacobian; //! Number of calls of the jacobian int nb_factorization; //! Number of factorization performed (may be > number of iterations) int nb_gradient_step; //! Number of gradient steps (too many gradient steps indicate a bad starting guess) int nb_crashing_iterations; //! Number of crashing iterations int nb_iterations; //! Number of iterations bool max_taken; //! Maximum step has been taken int nb_max_taken; //! Number of time the maximum has been taken int nb_consecutive_max_taken; //! Number of consecutive step at max length double current_residual; //! Current residual double current_update; //! Current update MiCPSolverReturnCode return_code; //! Return code MiCPPerformance(): nb_call_residuals(0), nb_call_jacobian(0), nb_factorization(0), nb_gradient_step(0), nb_crashing_iterations(0), nb_iterations(0), max_taken(false), nb_max_taken(0), nb_consecutive_max_taken(0), current_residual(INFINITY), current_update(INFINITY), return_code(MiCPSolverReturnCode::NotConvergedYet) {} //! \brief add two performance instances - useful when restarting a computation in case of failure MiCPPerformance& operator+=(const MiCPPerformance& other) { nb_call_residuals += other.nb_call_residuals; nb_call_jacobian += other.nb_call_jacobian; nb_factorization += other.nb_factorization; nb_gradient_step += other.nb_gradient_step; nb_crashing_iterations += other.nb_crashing_iterations; nb_iterations += other.nb_iterations; return_code = other.return_code; // we take the last one return *this; } }; //! The NCP function that are implemented enum class NCPfunction { penalizedFB, // Penalized Fischer-Burmeister function min // The minimum function }; } // end namespace micpsolver } // end namespace specmicp #endif //SPECMICP_MICPSOLVER_MICPSOLVERSTRUCTS_HPP diff --git a/src/micpsolver/micpsolverold.hpp b/src/micpsolver/micpsolverold.hpp index a89d7f8..1872468 100644 --- a/src/micpsolver/micpsolverold.hpp +++ b/src/micpsolver/micpsolverold.hpp @@ -1,321 +1,324 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMIC_MICPSOLVER_MICPSOLVEROLD_HPP #define SPECMIC_MICPSOLVER_MICPSOLVEROLD_HPP #include #include #include "micpsolver_structs.hpp" #include "ncp_function.hpp" //! \file micpsolver.hpp The MiCP solver namespace specmicp { namespace micpsolver { //! \brief Call a NCP-function //! //! @tparam ncp_t the NCP function to use //! @param a first argument //! @param b second argument //! @param t parameter of the NCP function //! template inline double ncp_function(double a, double b, double t); //! \brief Reformulate the jacobian using the NCP-function ncp_t //! //! @tparam ncp_t the NCP-function to use //! @param[in] neq number of equation //! @param[in] neq_free number of free variables //! @param[in] x the variables //! @param[in] r the residuals //! @param[in,out] jacobian the jacobian to reformulate //! @param[in,out] r_reformulated the reformulated residuals //! @param[in] t parameter of the NCP function template inline void reformulate_jacobian_helper( int neq, int neq_free, const Eigen::VectorXd& x, const Eigen::VectorXd& r, Eigen::MatrixXd& jacobian, Eigen::VectorXd& r_reformulated, double t ); //! \brief reformulate the result of the Newton system template inline void reformulate_result( int neq, int neq_free, Eigen::VectorXd& x, const Eigen::VectorXd& orig_r, Eigen::VectorXd& grad_phi, Eigen::VectorXd& update ); //! \brief The MiCP Solver //! //! Solve //! - \f$ G(u, v) = 0\f$ //! - \f$ 0 \leq v \perp H(u,v) \geq 0 \f$ //! //! \tparam Program a subclass of MiCPProg //! //! References : //! - \cite Munson2001 //! - \cite Facchinei2003 //! template class MiCPSolverOLD { public: //! \brief Constructor //! //! @param prog smart pointer toward an instance of a Program to solve MiCPSolverOLD(std::shared_ptr prog): m_program(prog), m_residuals(prog->total_variables()), m_phi_residuals(Eigen::VectorXd::Zero(prog->total_variables())), m_jacobian(prog->total_variables(),prog ->total_variables()), m_max_taken(false), m_consec_max(0) { } //! \brief Return a const reference to the options used by the algorithm const MiCPSolverOptions& get_options() const {return m_options;} //! \brief Return a reference to the options used by the algorithm MiCPSolverOptions& get_options() {return m_options;} //! \brief Set the options void set_options(const MiCPSolverOptions& options) {m_options = options;} //! \brief Return the number of equations int get_neq() const {return m_program->total_variables();} //! \brief Return the number of equations corresponding to the free variables (size of G) int get_neq_free() const {return m_program->nb_free_variables();} // Merit function // ############## //! \brief Reformulation for lower bounded variable double phi_lower_bounded(const double& x, const double& r, const double& l) const { return ncp_function(x-l, r, get_options().penalization_factor);} //! \brief Reformulation for a free variable double phi_free(const double& r) const { return r; } //! \brief Compute the norm of the update template double norm_update(const Eigen::VectorXd& update, const Eigen::VectorXd& solution) const { return (update.array().abs()/(solution.array().max(1)) ).matrix().template lpNorm

(); } // Residuals and jacobian // ---------------------- //! \brief Compute the residuals, store it in r //! //! @param[in] x the variables //! @param[out] r vector to store the residuals (must be of the same size as x) void compute_residuals(const Eigen::VectorXd& x, Eigen::VectorXd& r) { m_program->get_residuals(x, r); get_perf().nb_call_residuals += 1; } //! \brief Compute the residuals, use internal storage //! //! @param[in] x the variables void compute_residuals(const Eigen::VectorXd& x) { return compute_residuals(x, m_residuals); get_perf().nb_call_jacobian += 1; } //! \brief Compute the jacobian //! //! Assumes that the residual have been computed before //! //! @param[in] x the variables void compute_jacobian(Eigen::VectorXd& x) { m_program->get_jacobian(x, m_jacobian); } //! \brief Reformulation of the residuals //! //! Reformulate the problem - assumes that r, the residual, has been computed before //! //! @param[in] x the variables //! @param[in] r the residuals //! @param[out] r_phi a vector of size neq, which will contain the reformulated residuals void reformulate_residuals(const Eigen::VectorXd& x, const Eigen::VectorXd& r, Eigen::VectorXd& r_phi); //! \brief Reformulation of the residuals *inplace* //! //! @param[in] x the variables //! @param[in,out] r the residual, will contain the reformulated residuals void reformulate_residuals_inplace(const Eigen::VectorXd& x, Eigen::VectorXd &r); //! \brief Reformulation of the jacobian //! //! r is the original vector of residuals (not reformulated) void reformulate_jacobian(const Eigen::VectorXd& x ) { reformulate_jacobian_helper(get_neq(), get_neq_free(), x, m_residuals, m_jacobian, m_phi_residuals, get_options().penalization_factor); } //! \brief Compute the factors to scale the jacobian //! //! @param[in] jacobian the jacobian to scale (from the reformulated problem) //! @param[in] residual the residuals corresponding to the jacobian //! @param[out] rscaler scaling factors of the rows //! @param[out] cscaler scaling factors of the columns void scaling_jacobian(const Eigen::MatrixXd& jacobian, const Eigen::VectorXd& residual, Eigen::VectorXd& rscaler, Eigen::VectorXd& cscaler); // Algorithm // ######### //! \brief Solver the program using x as initial guess //! //! @param[in,out] x the initial guess, as output contains the solution (from the last iteration) MiCPSolverReturnCode solve(Eigen::VectorXd& x); //! \brief Setup the residuals //! //! @param[in] x the current solution void setup_residuals(const Eigen::VectorXd& x) { compute_residuals(x); reformulate_residuals(x, m_residuals, m_phi_residuals); } //! \brief Setup the jacobian //! //! @param[in] x the current solution void setup_jacobian(Eigen::VectorXd& x) { compute_jacobian(x); reformulate_jacobian(x); m_grad_phi = m_jacobian.transpose() * m_phi_residuals; } //! \brief Check for convergence //! //! @param nb_iterations the number of iterations //! @param update the update taken at the previous iteration //! @param solution the current solution //! @return a MiCPSolverReturnCode describing the state of the algorithm MiCPSolverReturnCode check_convergence(int nb_iterations, Eigen::VectorXd& update, Eigen::VectorXd& solution); //! \brief Solve the Newton system //! //! Assume that the Newton system has been formed //! //! \param[out] update the update to apply to the solution MiCPSolverReturnCode search_direction_calculation(Eigen::VectorXd& update); //! \brief Solve the Newton system - does not scale the jacobian //! //! Assume that the Newton system has been formed //! //! \param[out] update the update to apply to the solution MiCPSolverReturnCode search_direction_calculation_no_scaling(Eigen::VectorXd& update); //! \brief Linesearch //! //! Nonmonotone linesearch //! //! References : //! - \cite Dennis1983 //! - \cite Munson2001 //! int linesearch(Eigen::VectorXd& update, Eigen::VectorXd& x); //! \brief Crashing //! //! This function improves, if possible, the initial guess //! Reference : //! - \cite Munson2001 void crashing(Eigen::VectorXd& x); //! \brief Project variables on the feasible set void projection(Eigen::VectorXd& x); //! \brief Return a const reference to an instance of MiCPPerformance const MiCPPerformance& get_performance() {return m_perf;} protected: //! \brief Return a reference to an instance of MiCPPerformance MiCPPerformance& get_perf() {return m_perf;} private: //! \brief Return the step corrected step length if it is too long double is_step_too_long(Eigen::VectorXd& update); std::shared_ptr m_program; //!< Smart pointer of a program MiCPSolverOptions m_options; //!< The options MiCPPerformance m_perf; //!< The performance // Residuals and jacobian Eigen::VectorXd m_residuals; //!< The residuals Eigen::VectorXd m_phi_residuals; //!< The reformulated residuals Eigen::VectorXd m_grad_phi; //!< The gradient of the reformulated residuals Eigen::MatrixXd m_jacobian; //!< The jacobian std::vector m_max_merits; //!< Contains the m best value of the merit function bool m_max_taken; //!< True if the 'length' of the step was equal or bigger than the maximum step length int m_consec_max; //!< The number of consecutive step were the step length was equal or bigger than the maximum step length bool m_gradient_step_taken; //!< True if the update was computed using the gradient }; } // end namespace micpsolver } // end namespace specmicp // ###############// // Implementation // // ###############// #include "micpsolverold.inl" #endif // SPECMIC_MICPSOLVER_MICPSOLVER_HPP diff --git a/src/micpsolver/micpsolverold.inl b/src/micpsolver/micpsolverold.inl index b051241..445ff6d 100644 --- a/src/micpsolver/micpsolverold.inl +++ b/src/micpsolver/micpsolverold.inl @@ -1,634 +1,637 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "micpsolverold.hpp" // for syntaxic coloration... #include "estimate_cond_number.hpp" #include "utils/log.hpp" #include //! \file micpsolver.inl implementation of the MiCP solver namespace specmicp { namespace micpsolver { // Main algorithm // ############## template MiCPSolverReturnCode MiCPSolverOLD::solve(Eigen::VectorXd &x) { int cnt = 0; if (get_options().use_crashing) crashing(x); else setup_residuals(x); MiCPSolverReturnCode retcode = MiCPSolverReturnCode::NotConvergedYet; Eigen::VectorXd update(get_neq()); while (retcode == MiCPSolverReturnCode::NotConvergedYet) { DEBUG << "Iteration : " << cnt; SPAM << "Solution : \n" << x; m_program->hook_start_iteration(x, m_phi_residuals.norm()); setup_residuals(x); get_perf().current_residual = m_phi_residuals.norm(); SPAM << "Residuals : \n ----- \n" << m_phi_residuals << "\n ----- \n"; retcode = check_convergence(cnt, update, x); get_perf().return_code = retcode; if (retcode != MiCPSolverReturnCode::NotConvergedYet) break; ++cnt; m_max_taken = false; setup_jacobian(x); if(get_options().use_scaling) search_direction_calculation(update); else search_direction_calculation_no_scaling(update); reformulate_result(get_neq(), get_neq_free(), x, m_residuals, m_grad_phi, update); int termcode = linesearch(update, x); get_perf().current_update = update.norm(); DEBUG << "Return LineSearch : " << termcode; projection(x); get_perf().nb_iterations = cnt; } return retcode; } template MiCPSolverReturnCode MiCPSolverOLD::check_convergence(int nb_iterations, Eigen::VectorXd& update, Eigen::VectorXd& solution) { MiCPSolverReturnCode termcode = MiCPSolverReturnCode::NotConvergedYet; const double norm_residuals = m_phi_residuals.lpNorm(); if (norm_residuals < get_options().fvectol) { termcode = MiCPSolverReturnCode::ResidualMinimized; } else if (nb_iterations >0 and norm_update(update, solution) < get_options().steptol) { if (norm_residuals > get_options().threshold_stationary_point) { ERROR << "Stationary point detected !"; termcode = MiCPSolverReturnCode::StationaryPoint; } WARNING << "Error is minimized - may indicate a stationnary point"; termcode = MiCPSolverReturnCode::ErrorMinimized; } else if (nb_iterations > get_options().max_iter) { ERROR << "Maximum number of iteration reached (" << get_options().max_iter << ")"; termcode = MiCPSolverReturnCode::MaxIterations; } else if (m_max_taken) { ++m_consec_max; if (m_consec_max == get_options().maxiter_maxstep) { ERROR << "Divergence detected - Maximum step length taken two many times"; termcode = MiCPSolverReturnCode::MaxStepTakenTooManyTimes; } } else { m_consec_max = 0; } return termcode; } template MiCPSolverReturnCode MiCPSolverOLD::search_direction_calculation(Eigen::VectorXd& update) { Eigen::VectorXd rscaler(Eigen::VectorXd::Ones(m_jacobian.cols())); Eigen::VectorXd cscaler(Eigen::VectorXd::Ones(m_jacobian.rows())); scaling_jacobian(m_jacobian, m_phi_residuals, rscaler, cscaler); m_jacobian = rscaler.asDiagonal() * (m_jacobian) * cscaler.asDiagonal(); Eigen::ColPivHouseholderQR solver; m_gradient_step_taken = false; int m; for (m=0; m()); if (cond > get_options().condition_limit) { m_gradient_step_taken = true; m_jacobian += rscaler.asDiagonal() * ( lambda*Eigen::MatrixXd::Identity(m_jacobian.rows(),m_jacobian.cols())) * cscaler.asDiagonal(); continue; } update = solver.solve(-rscaler.cwiseProduct(m_phi_residuals + m*lambda*m_grad_phi)); update = cscaler.cwiseProduct(update); double descent_cond = m_grad_phi.dot(update); double norm_grad = m_grad_phi.norm(); double norm_update = update.norm(); if ( (descent_cond <= -get_options().factor_descent_condition*std::min(std::pow(norm_update,2),std::pow(norm_update,3))) and (descent_cond <= -get_options().factor_descent_condition*std::min(std::pow(norm_grad,2),std::pow(norm_grad,3))) ) break; // we have a solution ! m_gradient_step_taken = true; m_jacobian += rscaler.asDiagonal() * ( lambda* Eigen::MatrixXd::Identity(m_jacobian.rows(),m_jacobian.cols()) ) * cscaler.asDiagonal(); } DEBUG << "Gradient step : m = " << m; if (m == get_options().max_factorization_step) { INFO << "Full gradient step taken !"; update = -m_grad_phi; } return MiCPSolverReturnCode::NotConvergedYet; } template MiCPSolverReturnCode MiCPSolverOLD::search_direction_calculation_no_scaling(Eigen::VectorXd& update) { DEBUG << "Solving linear system"; Eigen::ColPivHouseholderQR solver; m_gradient_step_taken = false; int m; for (m=0; m()); if (cond > get_options().condition_limit) { continue; } update = solver.solve(-(m_phi_residuals + m*lambda*m_grad_phi)); double descent_cond = m_grad_phi.dot(update); double norm_grad = m_grad_phi.norm(); double norm_update = update.norm(); if ( (descent_cond <= -get_options().factor_descent_condition*std::min(std::pow(norm_update,2),std::pow(norm_update,3))) and (descent_cond <= -get_options().factor_descent_condition*std::min(std::pow(norm_grad,2),std::pow(norm_grad,3))) ) break; // we have a solution ! m_gradient_step_taken = true; m_jacobian += lambda*Eigen::MatrixXd::Identity(m_jacobian.rows(),m_jacobian.cols()); } DEBUG << "Gradient step : m = " << m; if (m ==4) { INFO << "Full gradient step taken !"; update = -m_grad_phi; } return MiCPSolverReturnCode::NotConvergedYet; } template void MiCPSolverOLD::crashing(Eigen::VectorXd &x) { DEBUG << "Crashing "; const double beta = 0.5; const double sigma = 1e-5; int cnt = 0; while (cnt < 10) { setup_residuals(x); setup_jacobian(x); m_grad_phi = m_jacobian.transpose()*m_phi_residuals; Eigen::VectorXd xp(get_neq()); int l=0; const int maxl = 10; while (l void MiCPSolverOLD::reformulate_residuals(const Eigen::VectorXd& x, const Eigen::VectorXd& r, Eigen::VectorXd& r_phi) { r_phi.resizeLike(r); r_phi.block(0, 0, get_neq_free(), 1) = r.block(0, 0, get_neq_free(), 1); for (int i = get_neq_free(); i void MiCPSolverOLD::reformulate_residuals_inplace(const Eigen::VectorXd& x, Eigen::VectorXd& r) { for (int i = get_neq_free(); i void MiCPSolverOLD:: scaling_jacobian( const Eigen::MatrixXd& jacobian, const Eigen::VectorXd& r_phi, Eigen::VectorXd& rscaler, Eigen::VectorXd& cscaler) { for (int i=0; i int MiCPSolverOLD::linesearch(Eigen::VectorXd& p, Eigen::VectorXd& x) { // Reference Algo A6.3.1 : Dennis and Schnabel (1983) DEBUG << "Linesearch"; Eigen::VectorXd xp(get_neq()); Eigen::VectorXd new_res(get_neq()); double fcp; m_max_taken = false; int retcode = 2; const double alpha = 1e-6; double newtlen = is_step_too_long(p); double init_slope = m_grad_phi.dot(p); double rellength = std::abs(p(0)); for (int i=1; imax_lambda(x, p); double lambda_prev = lambda; // non monotone linesearch // ----------------------- double merit_value = 0.5*m_phi_residuals.squaredNorm(); // new residual xp = x + lambda*p; compute_residuals(xp, new_res); reformulate_residuals_inplace(xp, new_res); fcp = 0.5*new_res.squaredNorm(); // Skip linesearch if enough progress is done if (fcp < get_options().coeff_accept_newton_step *merit_value) { if (m_max_merits.size() > 0) m_max_merits[m_max_merits.size()-1] = merit_value; else m_max_merits.push_back(merit_value); x = xp; return 0; } //std::cout << "Merit value : " << merit_value << std::endl; double mmax = merit_value; if (m_max_merits.size() > 0) { mmax = m_max_merits[m_max_merits.size()-1]; } if (m_max_merits.size() < 4) { m_max_merits.push_back(merit_value); if (merit_value < mmax) merit_value = (3*merit_value + mmax)/4; } else if (merit_value < mmax) { m_max_merits[3] = merit_value; merit_value = mmax; } if (m_gradient_step_taken) { merit_value *= 100; } //std::cout << "Merit value used : " << merit_value << std::endl; double fc = merit_value; double fcp_prev; int cnt = 0; do { fcp = 0.5*new_res.squaredNorm(); //std::cout << "fcp : " << fcp << "\n fc+alin : " << fc+alpha*lambda*init_slope << " # fc : " << fc << std::endl; if (fcp <= fc - std::min(-alpha*lambda*init_slope,(1-alpha)*fc)) //pg760 Fachinei2003 { retcode = 0; if (lambda ==1 and (newtlen > 0.99 * get_options().maxstep)) { m_max_taken = true; } break; } else if (lambda < minlambda) { retcode = 1; break; } else { double lambdatmp; if (cnt == 0) { // only a quadratic at the first lambdatmp = - init_slope / (2*(fcp - fc -init_slope)); } else { const double factor = 1 /(lambda - lambda_prev); const double x1 = fcp - fc - lambda*init_slope; const double x2 = fcp_prev - fc - lambda_prev*init_slope; const double a = factor * ( x1/(lambda*lambda) - x2/(lambda_prev*lambda_prev)); const double b = factor * ( -x1*lambda_prev/(lambda*lambda) + x2*lambda/(lambda_prev*lambda_prev)); if (a == 0) { // cubic interpolation is in fact a quadratic interpolation lambdatmp = - init_slope/(2*b); } else { const double disc = b*b-3*a*init_slope; lambdatmp = (-b+std::sqrt(disc))/(3*a); } if (lambdatmp > 0.5*lambda ) lambdatmp = 0.5*lambda; } lambda_prev = lambda; fcp_prev = fcp; if (lambdatmp < 0.1*lambda) { lambda = 0.1 * lambda; } else { lambda = lambdatmp; } } xp = x + lambda*p; compute_residuals(xp, new_res); reformulate_residuals_inplace(xp, new_res); ++cnt; } while(retcode == 2 and cnt < 100); DEBUG << "Lambda : " << lambda; if (cnt == 100) { ERROR << "Too much linesearch iterations ! We stop"; } x = xp; p = lambda*p; return retcode; } // Projection of the variables onto the feasible set template void MiCPSolverOLD::projection(Eigen::VectorXd &x) { for (int i=0; inb_complementarity_variables(); ++i) { if (x(i+m_program->nb_free_variables()) < get_options().projection_min_variable) { x(i+m_program->nb_free_variables()) = 0; } } } template double MiCPSolverOLD::is_step_too_long(Eigen::VectorXd& update) { double steplength = update.norm(); if (steplength > get_options().maxstep) { m_max_taken = true; update = get_options().maxstep / steplength * update; steplength = get_options().maxstep; } return steplength; } // ================================================= // // // // NCP functions and reformulation // // // // ================================================= // template <> inline double ncp_function(double a, double b, double t) { return penalized_fisher_burmeister(a, b, t); } template <> inline double ncp_function(double a, double b, double _) { return std::min(a, b); } template <> inline void reformulate_jacobian_helper( int neq, int neq_free, const Eigen::VectorXd& x, const Eigen::VectorXd& r, Eigen::MatrixXd& jacobian, Eigen::VectorXd& _, double t ) { // set the z vector : contains 1 for degenerate points Eigen::VectorXd z(Eigen::VectorXd::Zero(neq)); for (int i=neq_free; i 0) and (x(i) >0)) { c -= (1-lambda)*r(i); d -= (1-lambda)*x(i); } grad_fi = d*grad_fi; grad_fi(i) += c; } jacobian.block(i, 0, 1, neq) = grad_fi.transpose(); } } template <> inline void reformulate_jacobian_helper( int neq, int neq_free, const Eigen::VectorXd& x, const Eigen::VectorXd& r, Eigen::MatrixXd& jacobian, Eigen::VectorXd& r_phi, double _ ) { std::vector to_keep; to_keep.reserve(10); Eigen::VectorXd to_remove(neq-neq_free); for (int i=neq_free; i= r(i)) { to_remove(i-neq_free) = 0; to_keep.push_back(i); } else to_remove(i-neq_free) = x(i); } r_phi.block(0, 0, neq_free, 1) -= jacobian.block(0, neq_free, neq_free, neq-neq_free)*to_remove; int new_i = neq_free; for (auto it=to_keep.begin(); it!=to_keep.end(); ++it) { //r_phi.block(0, 0, neq_free, 1) += x(*it)*jacobian.block(0, *it, neq_free, 1); jacobian.block(new_i, 0, 1, neq_free) = jacobian.block(*it, 0, 1, neq_free); // the bottom right corner is 0 jacobian.block(0, new_i, neq_free, 1) = jacobian.block(0, *it, neq_free, 1); r_phi(new_i) = r_phi(*it); ++new_i; } r_phi.conservativeResize(new_i); jacobian.conservativeResize(new_i, new_i); DEBUG << jacobian; } template <> inline void reformulate_result( int neq, int neq_free, Eigen::VectorXd& x, const Eigen::VectorXd& orig_r, Eigen::VectorXd& grad_phi, Eigen::VectorXd& update ) {} template <> inline void reformulate_result( int neq, int neq_free, Eigen::VectorXd& x, const Eigen::VectorXd& orig_r, Eigen::VectorXd& grad_phi, Eigen::VectorXd& update ) { //std::cout << " Update \n ------- \n " << update << std::endl; int tot_to_keep = 0; for (int i=neq_free; i= orig_r(i)) ++tot_to_keep; } //std::cout << " update \n ------ \n" << update.block(neq_free, 0, tot_to_keep, 1) << std::endl; update.conservativeResize(neq); grad_phi.conservativeResize(neq); int kept_i = 1; for (int i=neq-1; i>=neq_free; --i) { // we go backwards to avoid extra copies //std::cout << i << " # " << x(i) << " - " << orig_r(i) << std::endl; if (x(i) >= orig_r(i)) { //std::cout << i << std::endl; update(i) = update(neq_free+(tot_to_keep-kept_i)); //std::cout << update(i) << std::endl; grad_phi(i) = grad_phi(neq_free+(tot_to_keep-kept_i)); ++kept_i; } else { //x(i) = 0.0; //update(i) = 0.0; update(i) = -x(i); grad_phi(i) = x(i); } } } } // end namespace micpsolver } // end namespace specmicp diff --git a/src/micpsolver/ncp_function.hpp b/src/micpsolver/ncp_function.hpp index e04ef06..971945a 100644 --- a/src/micpsolver/ncp_function.hpp +++ b/src/micpsolver/ncp_function.hpp @@ -1,88 +1,91 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_MICPSOLVE_NCPFUNCTION_HPP #define SPECMICP_MICPSOLVE_NCPFUNCTION_HPP #include //! \file ncp_function.hpp implements the ncp function namespace specmicp { namespace micpsolver { //! \brief The Fisher-Burmeister NCP-function //! //! @param a a scalar, first argument of the NCP-function //! @param b a scalar, second argument of the NCP-function //! //! References: //! - \cite Munson2001 //! - \cite Facchinei2003 template ScalarT fisher_burmeister(ScalarT a, ScalarT b) { ScalarT s = std::abs(a) + std::abs(b); if (s != 0) { s = s*std::sqrt((a*a)/(s*s) + (b*b)/(s*s)); } if ( a + b <= 0) { return s - (a + b); } else { return -2*a*b/(s + (a+b)); } } //! \brief The penalized Fisher-Burmeister NCP-function //! //! @param t in (0, 1), penalization factor //! @param a a scalar, first argument of the NCP-function //! @param b a scalar, second argument of the NCP-function //! //! References: //! - \cite Chen1997a //! - \cite Chen2000 //! - \cite Munson2001 template inline ScalarT penalized_fisher_burmeister(ScalarT a, ScalarT b, ScalarT t) { assert(t >= 0); assert(t <= 1); return t*fisher_burmeister(a,b)-(1-t)*std::max(0.0, a)*std::max(0.0, b); } } // end namespace micpsolver } // end namespace specmicp #endif // SPECMICP_MICPSOLVE_NCPFUNCTION_HPP diff --git a/src/odeint/butcher_tableau.hpp b/src/odeint/butcher_tableau.hpp index bf2057a..37e2f1f 100644 --- a/src/odeint/butcher_tableau.hpp +++ b/src/odeint/butcher_tableau.hpp @@ -1,103 +1,107 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ + #ifndef SPECMICP_ODEINT_BUTCHERTABLEAU_HPP #define SPECMICP_ODEINT_BUTCHERTABLEAU_HPP //! \file butcher_tableau.hpp Butcher tableau for embedded runge kutta method #include #include "common.hpp" namespace specmicp { namespace odeint { template class ButcherTableau { public: static const int RK_order = order; static const int RK_evaluations = s+1; ButcherTableau(const std::array& aa, const std::array, s>& ba, const std::array& ca, const std::array& csa ): m_a(aa), m_b(ba), m_c(ca), m_cs(csa) {} ButcherTableau(std::array&& aa, std::array, s>&& ba, std::array&& ca, std::array&& csa ): m_a(aa), m_b(ba), m_c(ca), m_cs(csa) {} double a(int i) const {return m_a[i-2];} double b(int i, int j) const {return m_b[i-2][j-1];} double c(int i) const {return m_c[i-1];} double cs(int i) const {return m_cs[i-1];} private: std::array m_a; std::array, s> m_b; std::array m_c; std::array m_cs; }; const ButcherTableau<5, 5> butcher_cash_karp45({1.0/5.0, 3.0/10.0, 3.0/5.0, 1.0, 7.0/8.0}, {{{1.0/5.0, 0, 0, 0, 0}, {3.0/40.0, 9.0/40.0, 0, 0, 0}, {3.0/10.0, -9.0/10.0, 6.0/5.0, 0, 0}, {-11.0/54.0, 5.0/2.0, -70.0/27.0, 35.0/27.0, 0}, {1631.0/55296.0, 175.0/512.0, 575.0/13824.0, 44275.0/110592.0, 253.0/4096.0} }}, {37.0/378.0, 0.0, 250.0/621.0, 125.0/594.0, 0.0, 512.0/1771.0}, {2825.0/27648.0, 0.0, 18575.0/48384.0, 13525.0/55296.0, 277.0/14336.0, 1.0/4.0} ); using ButcherTableauCashKarp_t = ButcherTableau<5, 5>; const ButcherTableau<5, 6> butcher_dormand_prince45( {1.0/5.0, 3.0/10.0, 4.0/5.0, 8.0/9.0, 1.0, 1.0}, { {{1.0/5.0, 0, 0, 0, 0, 0}, {3.0/40.0, 9.0/40.0, 0, 0, 0, 0}, {44.0/45.0, -56.0/15.0, 32.0/9.0, 0, 0, 0}, {19372.0/6561.0, -25360.0/2187.0, 64448.0/6561.0, -212.0/729.0, 0, 0}, {9017.0/3168.0, -355.0/33.0, 46732.0/5247.0, 49.0/176.0, -5103.0/18656.0, 0}, {35.0/384.0, 0.0, 500.0/1113.0, 125.0/192.0, -2187.0/6784.0, 11.0/84.0} }}, {35.0/384.0, 0.0, 500.0/1113.0, 125.0/192.0, -2187.0/6784.0, 11.0/84.0, 0.0}, {5179.0/57600.0, 0.0, 7571.0/16695.0, 393.0/640.0, -92097.0/339200.0, 187.0/2100.0, 1.0/40.0} ); using ButcherTableauDormandPrince_t = ButcherTableau<5, 6>; } // end namespace odeint } // end namespace specmicp #endif // SPECMICP_ODEINT_BUTCHERTABLEAU_HPP diff --git a/src/odeint/odeint_types.hpp b/src/odeint/odeint_types.hpp index 8e9af14..d833098 100644 --- a/src/odeint/odeint_types.hpp +++ b/src/odeint/odeint_types.hpp @@ -1,119 +1,122 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_ODEINT_ODEINTTYPES_HPP #define SPECMICP_ODEINT_ODEINTTYPES_HPP //! \file odeint_types.hpp common types for odeint #include "common.hpp" #include #include namespace specmicp { namespace odeint { namespace internal { //! \brief implementation for the vector type (which may not be a vector for dim=1) template struct vector_trait { using type = Eigen::Matrix; }; //! Specialisation for dimension 1 (scalar) template <> struct vector_trait<1> { using type = scalar_t; }; //! Specialization for dimension 2 (fixed-size vector) template <> struct vector_trait<2> { using type = Eigen::Matrix; }; //! Specialization for dimension 3 (fixed-size vector) template <> struct vector_trait<3> { using type = Eigen::Matrix; }; } // end namespace internal //! The vector type template using vector_t = typename internal::vector_trait::type; //! Return the maximum coefficient of the vector template inline scalar_t max_coeff(const vector_t& vec) {return vec.maxCoeff();} template <> inline scalar_t max_coeff<1>(const vector_t<1>& vec) {return vec;} //! \brief Type of the function f in dy/dx=f(x,y) template using rhs_f = std::function&, vector_t&)>; //! \brief Return true of all members of 'vec' are non-negative template inline bool is_nonnegative(vector_t& vec) { return (vec.array() >= Eigen::VectorXd::Zero(vec.rows()).array()).all(); } template <> inline bool is_nonnegative<1>(vector_t<1>& vec) { return vec >= 0.0; } //! \brief Project to the positive quadrant template inline void set_non_negative(vector_t& vec) { vec = vec.cwiseMax(Eigen::VectorXd::Zero(vec.rows())); } template <> inline void set_non_negative<1>(vector_t<1>& vec) { vec = std::max(0.0, vec); } } // end namespace odeint } // end namespace specmicp #endif // SPECMICP_ODEINT_ODEINTTYPES_HPP diff --git a/src/odeint/runge_kutta_step.hpp b/src/odeint/runge_kutta_step.hpp index be650ab..063e433 100644 --- a/src/odeint/runge_kutta_step.hpp +++ b/src/odeint/runge_kutta_step.hpp @@ -1,196 +1,195 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- - - Module : odeint - - File : runge_kutta_step - - Author : Fabien Georget - -Copyright (c) 2014, Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_ODEINT_RUNGEKUTTASTEP_HPP #define SPECMICP_ODEINT_RUNGEKUTTASTEP_HPP //! \file runge_kutta_step algorithm for embedded runge kutta #include "odeint_types.hpp" #include "butcher_tableau.hpp" #include "runge_kutta_step_structs.hpp" #include "utils/options_handler.hpp" namespace specmicp { namespace odeint { struct StepLength { static constexpr scalar_t not_available = -1.0; scalar_t test; scalar_t did; scalar_t next; scalar_t total; StepLength(scalar_t h_test): test(h_test), did(not_available), next(not_available), total(0.0) {} StepLength(scalar_t h_test, scalar_t h_total): test(h_test), did(not_available), next(not_available), total(h_total) {} void get_next() { test=next; did=not_available; next=not_available; } bool is_next_available() {return next != not_available;} bool is_total_time_fixed() {return total > 0.0;} scalar_t remaining(scalar_t t) {return (total-t);} }; //! \brief Base class for computing a step of the Range Kutta algorithm template class EmbeddedRungeKuttaStep : public OptionsHandler { public: using vec_t = vector_t; EmbeddedRungeKuttaStep( const rhs_f& rhs, const butcher_tableau_t& butcher): m_rhs(rhs), m_butcher(butcher) {} EmbeddedRungeKuttaStep( const rhs_f& rhs, const butcher_tableau_t& butcher, EmbeddedRungeKuttaStepOptions& options ): OptionsHandler(options), m_rhs(rhs), m_butcher(butcher) {} //! \brief compute a step //! //! \param y initial value //! \param dydx initial value of the right hand site //! \param x value of the integration variable //! \param timestep the integration step //! \param y_out value at the end of the step (y+timestep) //! \param y_err estimation of the truncation error void run_step( const vec_t& y, const vec_t& dydx, scalar_t x, scalar_t timestep, vec_t& y_out, vec_t& y_err); protected: //! Return the value of the right hand side at x for value y void get_rhs( scalar_t x, const vector_t& y, vec_t& dydx ) {return m_rhs(x, y, dydx);} //! Return the Butcher tableau butcher_tableau_t& butcher() {return m_butcher;} private: rhs_f m_rhs; butcher_tableau_t m_butcher; }; //! Embedded Runge Kutta of fifth order template class EmbeddedRungeKuttaStep45: EmbeddedRungeKuttaStep { public: using base = EmbeddedRungeKuttaStep; using vec_t = typename base::vec_t; using base::butcher; using base::get_rhs; using base::get_options; //check that template argument are consistent static_assert(butcher_tableau_t::RK_order == 5, "The butcher tableau must correspond to a Runge-Kutta method of order 5"); static_assert(butcher_tableau_t::RK_evaluations == 6 || butcher_tableau_t::RK_evaluations == 7, "The number of functions evaluations must be 6 or 7 for an embedded Runge-Kutta method"); EmbeddedRungeKuttaStep45(const rhs_f& rhs, const butcher_tableau_t& butcher): base(rhs, butcher) { } EmbeddedRungeKuttaStep45( const rhs_f& rhs, const butcher_tableau_t& butcher, EmbeddedRungeKuttaStepOptions options ): base(rhs, butcher, options) { } void run_step(const vec_t& y, const vec_t& dydx, scalar_t x, scalar_t timestep, vec_t& y_out, vec_t& y_err); void rk_step(vector_t &y, const vector_t& dydx, double& x, StepLength& stepl); }; //! typedef to create a Dormant-Prince method template using DormandPrinceStep = EmbeddedRungeKuttaStep45; template DormandPrinceStep get_dormand_prince_step(const rhs_f& rhs) {return DormandPrinceStep(rhs, butcher_dormand_prince45);} //! typedef to create a Cash-Karp method template using CashKarpStep = EmbeddedRungeKuttaStep45; template CashKarpStep get_cash_karp_step(const rhs_f& rhs) {return CashKarpStep(rhs, butcher_cash_karp45);} template T get_rk_step(const rhs_f& rhs) { if (std::is_same>::value) return get_cash_karp_step(rhs); else if (std::is_same>::value) return get_dormand_prince_step(rhs); } } // end namespace odeint } // end namespace specmicp #include "runge_kutta_step.inl" #endif // SPECMICP_ODEINT_RUNGEKUTTASTEP_HPP diff --git a/src/odeint/runge_kutta_step.inl b/src/odeint/runge_kutta_step.inl index fdae2a2..1ff6ca3 100644 --- a/src/odeint/runge_kutta_step.inl +++ b/src/odeint/runge_kutta_step.inl @@ -1,120 +1,123 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "runge_kutta_step.hpp" // syntaxic coloration only namespace specmicp { namespace odeint { template void EmbeddedRungeKuttaStep45::run_step(const vec_t& y, const vec_t& dydx, scalar_t x, scalar_t timestep, vec_t& y_out, vec_t& y_err) { vec_t ak2, ak3, ak4, ak5, ak6; vec_t ytemp; ytemp = y + butcher().b(2, 1)*timestep*dydx; get_rhs(x + butcher().a(2)*timestep, ytemp, ak2); ytemp = y + timestep*(butcher().b(3,1)*dydx + butcher().b(3, 2)*ak2); get_rhs(x + butcher().a(3)*timestep, ytemp, ak3); ytemp = y + timestep*(butcher().b(4,1)*dydx + butcher().b(4, 2)*ak2 + butcher().b(4, 3)*ak3); get_rhs(x + butcher().a(4)*timestep, ytemp, ak4); ytemp = y + timestep*(butcher().b(5,1)*dydx + butcher().b(5, 2)*ak2 + butcher().b(5, 3)*ak3 + butcher().b(5, 4)*ak4); get_rhs(x + butcher().a(5)*timestep, ytemp, ak5); ytemp = y + timestep*(butcher().b(6,1)*dydx + butcher().b(6, 2)*ak2 + butcher().b(6, 3)*ak3 + butcher().b(6, 4)*ak4 + butcher().b(6, 5)*ak5); get_rhs(x + butcher().a(6)*timestep, ytemp, ak6); if (butcher_tableau_t::RK_evaluations == 6) { y_out = y + timestep*(butcher().c(1)*dydx + butcher().c(2)*ak2 + butcher().c(3)*ak3 + butcher().c(4)*ak4 + butcher().c(5)*ak5 + butcher().c(6)*ak6); y_err = timestep * ( (butcher().c(1) - butcher().cs(1))*dydx + (butcher().c(2) - butcher().cs(2))*ak2 + (butcher().c(3) - butcher().cs(3))*ak3 + (butcher().c(4) - butcher().cs(4))*ak4 + (butcher().c(5) - butcher().cs(5))*ak5 + (butcher().c(6) - butcher().cs(6))*ak6 ); } else { vec_t ak7; ytemp = y + timestep*(butcher().b(7,1)*dydx + butcher().b(7, 2)*ak2 + butcher().b(7, 3)*ak3 + butcher().b(7, 4)*ak4 + butcher().b(7, 5)*ak5 + butcher().b(7, 6)*ak6); get_rhs(x + butcher().a(7)*timestep, ytemp, ak7); y_out = y + timestep*(butcher().c(1)*dydx + butcher().c(2)*ak2 + butcher().c(3)*ak3 + butcher().c(4)*ak4 + butcher().c(5)*ak5 + butcher().c(6)*ak6 + butcher().c(7)*ak7); y_err = timestep * ( (butcher().c(1) - butcher().cs(1))*dydx + (butcher().c(2) - butcher().cs(2))*ak2 + (butcher().c(3) - butcher().cs(3))*ak3 + (butcher().c(4) - butcher().cs(4))*ak4 + (butcher().c(5) - butcher().cs(5))*ak5 + (butcher().c(6) - butcher().cs(6))*ak6 + (butcher().c(7) - butcher().cs(7))*ak7 ); } if (get_options().non_negativity) set_non_negative(y_out); } template void EmbeddedRungeKuttaStep45::rk_step(vector_t& y, const vector_t& dydx, double& x, StepLength& stepl) { vector_t y_err; vector_t y_temp; double h = stepl.test; double xnew; scalar_t errmax; for (int i=0; i(y_err) / get_options().eps; if (errmax < 1) break; double htemp = get_options().safety*h*std::pow(errmax, get_options().p_shrink); h = (h >= 0.0 ? std::max(htemp, 0.1*h) : std::min(htemp, 0.1*h)); xnew = x+h; if (xnew == x) {throw std::runtime_error("stepsize underflow");} } stepl.did = h; x += h; if (errmax > get_options().errcon) {stepl.next = get_options().safety*h*std::pow(errmax, get_options().p_grow);} else {stepl.next = 5.0*h;} y = y_temp; } } // end namespace odeint } // end namespace specmicp diff --git a/src/odeint/runge_kutta_step_structs.hpp b/src/odeint/runge_kutta_step_structs.hpp index a0ea1a5..47fbb2b 100644 --- a/src/odeint/runge_kutta_step_structs.hpp +++ b/src/odeint/runge_kutta_step_structs.hpp @@ -1,64 +1,67 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_ODEINT_RUNGEKUTTASTEPSTRUCTS_HPP #define SPECMICP_ODEINT_RUNGEKUTTASTEPSTRUCTS_HPP #include "common.hpp" namespace specmicp { namespace odeint { struct EmbeddedRungeKuttaStepOptions { scalar_t safety; scalar_t p_grow; scalar_t p_shrink; scalar_t errcon; scalar_t max_try; scalar_t eps; bool non_negativity; EmbeddedRungeKuttaStepOptions(): safety(0.9), p_grow(-0.2), p_shrink(-0.25), errcon(1.89e-4), max_try(20), eps(1e-5), non_negativity(false) {} }; } // end namespace odeint } // end namespace specmicp #endif// SPECMICP_ODEINT_RUNGEKUTTASTEPSTRUCTS_HPP diff --git a/src/physics/constants.hpp b/src/physics/constants.hpp index 5ce0b59..5b4f59a 100644 --- a/src/physics/constants.hpp +++ b/src/physics/constants.hpp @@ -1,52 +1,55 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_CONSTANTS_CONSTANTS_HPP #define SPECMICP_CONSTANTS_CONSTANTS_HPP //! \file constants Contains physical constants namespace specmicp { namespace constants { const double gas_constant = 8.3144621; // J / K mol const double water_density_25 = 997.05; // kg / m^3 const double water_density_25_kgl = 0.99705; // kg / L const double Adebye = 0.5092; //!< constant 'A' for Debye-Huckel activity coefficient const double Bdebye = 0.3283; //!< constant 'B' for Debye-Huckel activity coefficient const double faraday_constant = 9.6485339924e4 ; //! the Faraday constant } // end namespace constants } // end namespace specmicp #endif // SPECMICP_CONSTANTS_CONSTANTS_HPP diff --git a/src/physics/laws.hpp b/src/physics/laws.hpp index dd78093..35f3795 100644 --- a/src/physics/laws.hpp +++ b/src/physics/laws.hpp @@ -1,88 +1,91 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_LAWS_LAWS_HPP #define SPECMICP_LAWS_LAWS_HPP //! \file laws Simple physical laws #include "common.hpp" #include "constants.hpp" #include "units.hpp" #include namespace specmicp { namespace laws { inline constexpr scalar_t pressure_perfect_gas(scalar_t n, scalar_t V, scalar_t T=298.15) { return n*constants::gas_constant*T/V; } inline constexpr scalar_t mole_perfect_gas(scalar_t P, scalar_t V, scalar_t T=298.15) { return P*V/(constants::gas_constant*T); } inline scalar_t debye_huckel(scalar_t sqrtI, scalar_t zi, scalar_t ao) { if (zi != 0) { scalar_t tmp = - constants::Adebye*std::pow(2, zi)*sqrtI; tmp /= (1 + ao*constants::Bdebye*sqrtI); return tmp; } else return 0; } inline scalar_t extended_debye_huckel(scalar_t I, scalar_t sqrtI, scalar_t zi, scalar_t ao, scalar_t bdot) { scalar_t tmp = debye_huckel(sqrtI, zi, ao); return tmp + bdot*I; } inline scalar_t extended_debye_huckel(scalar_t I, scalar_t zi, scalar_t ao, scalar_t bdot) { scalar_t tmp = debye_huckel(std::sqrt(I), zi, ao); return tmp + bdot*I; } inline scalar_t density_water(scalar_t temperature, units::LengthUnit length_unit, units::MassUnit mass_unit) { scalar_t scaling = 1.0; if (mass_unit == units::MassUnit::gram) scaling *= 1e-3; if (length_unit == units::LengthUnit::centimeter) scaling *= 1e-6; else if (length_unit == units::LengthUnit::decimeter) scaling = 1e-3; return scaling*constants::water_density_25; } } // end namespace laws } // end namespace specmicp #endif // SPECMICP_LAWS_LAWS_HPP diff --git a/src/physics/units.hpp b/src/physics/units.hpp index c6ce065..45a6192 100644 --- a/src/physics/units.hpp +++ b/src/physics/units.hpp @@ -1,136 +1,139 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_UNITS_UNITS #define SPECMICP_UNITS_UNITS #include "common.hpp" //! \file units.hpp units conversion namespace specmicp { namespace units { //! units used for length enum class LengthUnit { meter, decimeter, centimeter }; //! units used for mass enum class MassUnit { kilogram, gram }; //! \brief Simple struct which contains the unit information struct UnitsSet { MassUnit mass; //!< The unit to use for mass LengthUnit length; //!< The unit to use for length (also area and volume) //! \brief Defaults are the SI unit system UnitsSet(): mass(MassUnit::kilogram), length(LengthUnit::meter) {} }; //! \brief Base class that handles the units //! //! To be inherited by other classes that need units class UnitBaseClass { public: UnitBaseClass() {} UnitBaseClass(UnitsSet units): m_units(units) {} //! \brief Return the units UnitsSet get_units() {return m_units;} //! \brief Set the units void set_units(UnitsSet units) {m_units = units;} //! \brief Return the Mass unit MassUnit mass_unit() const {return m_units.mass;} //! \brief Return the Length unit LengthUnit length_unit() const {return m_units.length;} //! \brief Return the mass unit MassUnit& mass_unit() {return m_units.mass;} //! \brief Return the length unit LengthUnit& length_unit() {return m_units.length;} private: UnitsSet m_units; }; // Temperature // ----------- //! Convert a temperature from Celsius to Kelvin inline constexpr scalar_t celsius(scalar_t tc) {return tc + 273.15;} //! Convert a temperature from Kelvin to Celsius inline constexpr scalar_t to_celsius(scalar_t tk) { return tk - 273.15;} // Volume // ------ //! Convert liter to cubic meter inline constexpr scalar_t liter(scalar_t vl) {return 1e-3*vl;} //! convert cubic meter to liter inline constexpr scalar_t to_liter(scalar_t vcm) {return 1e3*vcm;} // Pressure // -------- inline scalar_t convert_pressure(scalar_t pressure_si, LengthUnit length_unit) { scalar_t pressure; switch (length_unit) { case LengthUnit::meter: pressure = pressure_si; break; case LengthUnit::decimeter: pressure = 1e-2*pressure_si; break; case LengthUnit::centimeter: pressure = 1e-4*pressure_si; } return pressure; } } // end namespace units } // end namespace specmicp #endif // SPECMICP_UNITS_UNITS diff --git a/src/reactmicp.hpp b/src/reactmicp.hpp index badfc9e..5f2c020 100644 --- a/src/reactmicp.hpp +++ b/src/reactmicp.hpp @@ -1,57 +1,60 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ //! \file reactmicp.hpp //! \brief Include this file to use ReactMiCP #include "common.hpp" #include "specmicp.hpp" #include "reactmicp/systems/saturated_react/variables.hpp" #include "reactmicp/systems/saturated_react/equilibrium_stagger.hpp" #include "reactmicp/systems/saturated_react/transport_stagger.hpp" #include "reactmicp/systems/saturated_react/init_variables.hpp" #include "reactmicp/solver/reactive_transport_solver.hpp" #include "reactmicp/solver/reactive_transport_solver_structs.hpp" #include "reactmicp/solver/staggers_base/upscaling_stagger_base.hpp" #include "reactmicp/solver/staggers_base/stagger_structs.hpp" #include "reactmicp/solver/timestepper.hpp" #include "database/database.hpp" #include "dfpm/mesh.hpp" #include "reactmicp/solver/runner.hpp" #include "utils/io/meshes.hpp" #include "utils/io/reactive_transport.hpp" #include "utils/io/saturated_react.hpp" #include "utils/io/units.hpp" diff --git a/src/reactmicp/equilibrium_curve/chemistry.cpp b/src/reactmicp/equilibrium_curve/chemistry.cpp index 0e68645..2f2fbd5 100644 --- a/src/reactmicp/equilibrium_curve/chemistry.cpp +++ b/src/reactmicp/equilibrium_curve/chemistry.cpp @@ -1,134 +1,137 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "chemistry.hpp" #include "specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include "specmicp/adimensional/adimensional_system_solver.hpp" #include "utils/log.hpp" #include namespace specmicp { namespace reactmicp { namespace eqcurve { // EquilibriumCurveSpeciation:: void EquilibriumCurveSpeciation::output() { index_t size = m_eqcurve.rows(); if (m_cnt == size) m_eqcurve.conservativeResize(size+500, 4); m_eqcurve.block(size, 0, m_eqcurve.rows()-size, 4).setZero(); AdimensionalSystemSolutionExtractor sol(current_solution(), m_data, get_units()); m_eqcurve(m_cnt, 0) = sol.total_solid_concentration(m_idc); m_eqcurve(m_cnt, 1) = sol.total_aqueous_concentration(m_idc); m_eqcurve(m_cnt, 2) = sol.porosity(); m_eqcurve(m_cnt, 3) = m_eqcurve(m_cnt, 2)>0.92?2.219e-5:1e4*std::exp(9.95*m_eqcurve(m_cnt, 2)-29.08); std::cout << m_eqcurve(m_cnt, 0) << " \t " << m_eqcurve(m_cnt, 1) << std::endl; } Matrix EquilibriumCurveSpeciation::get_equilibrium_curve(scalar_t end_total_concentration, scalar_t delta) { m_cnt = 0; solve_first_problem(); output(); AdimensionalSystemSolutionExtractor sol(current_solution(), m_data, get_units()); index_t nb_steps = std::abs(end_total_concentration - constraints().total_concentrations(m_idc))/( std::abs(delta)*sol.total_aqueous_concentration(m_idc)); std::cout << nb_steps << std::endl; m_eqcurve = Matrix::Zero(nb_steps, 4); m_delta = delta; ///(nb_steps-1); while (constraints().total_concentrations(m_idc) > end_total_concentration) { //std::cout << m_cnt << " - " << conditions().total_concentrations(m_idc) << std::endl; run_step(); ++m_cnt; } m_eqcurve.conservativeResize(m_cnt, 4); return m_eqcurve; } void EquilibriumCurveSpeciation::update_problem() { Vector diff_conc = get_perturbation(); scalar_t coeff = m_delta; for (index_t component: m_data->range_component()) { if (std::abs(constraints().total_concentrations(component)) < 1e-4) { constraints().total_concentrations(component) = 0.0; diff_conc(component) = 0.0; } if (constraints().total_concentrations(component) != 0 and std::copysign(1.0, constraints().total_concentrations(component) + coeff*diff_conc(component)) != std::copysign(1.0, constraints().total_concentrations(component)) ) { //std::cout << "Component : " << component << std::endl; coeff = std::copysign(0.9*constraints().total_concentrations(component), m_delta); coeff /= diff_conc(component); } } //std::cout << "Update : " << std::endl << coeff*diff_conc << std::endl; constraints().total_concentrations += coeff*diff_conc; // std::cout << "total concentrations : " << std::endl << conditions().total_concentrations << std::endl; } Vector EquilibriumCurveSpeciation::get_perturbation() { AdimensionalSystemSolutionExtractor sol(current_solution(), m_data, get_units()); Vector tot_aq_conc(m_data->nb_component()); tot_aq_conc.setZero(); for (index_t component: m_data->range_aqueous_component()) { tot_aq_conc(component) = sol.total_aqueous_concentration(component); } //tot_aq_conc *= m_delta/tot_aq_conc.norm(); return tot_aq_conc; } void EquilibriumCurveSpeciation::error_handling(std::string msg) const { ERROR << msg; ERROR << " Total concentration " << std::endl << constraints().total_concentrations << std::endl; throw std::runtime_error(msg); } } // end namespace eqcurve } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/equilibrium_curve/chemistry.hpp b/src/reactmicp/equilibrium_curve/chemistry.hpp index 5c3a9dc..a9df1f8 100644 --- a/src/reactmicp/equilibrium_curve/chemistry.hpp +++ b/src/reactmicp/equilibrium_curve/chemistry.hpp @@ -1,86 +1,89 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_EQUILIBRIUMCURVE_CHEMISTRY_HPP #define SPECMICP_REACTMICP_EQUILIBRIUMCURVE_CHEMISTRY_HPP #include "specmicp/adimensional/equilibrium_curve.hpp" #include "physics/units.hpp" namespace specmicp { namespace reactmicp { //! \namespace eqcurve Equilibrium approach to reactive transport namespace eqcurve { class EquilibriumCurveSpeciation: public EquilibriumCurve, public units::UnitBaseClass { public: EquilibriumCurveSpeciation( RawDatabasePtr thedatabase, AdimensionalSystemConstraints constraints, index_t id_component, AdimensionalSystemSolverOptions options ): EquilibriumCurve(thedatabase, constraints), UnitBaseClass(options.units_set), m_data(thedatabase), m_idc(id_component) { solver_options() = options; } void output(); void update_problem(); Matrix get_equilibrium_curve(scalar_t end_total_concentration, scalar_t delta); Vector get_perturbation(); void error_handling(std::string msg) const; private: RawDatabasePtr m_data; index_t m_idc; Matrix m_eqcurve; index_t m_cnt; scalar_t m_delta; }; } // end namespace eqcurve } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_EQUILIBRIUMCURVE_CHEMISTRY_HPP diff --git a/src/reactmicp/equilibrium_curve/eqcurve_coupler.cpp b/src/reactmicp/equilibrium_curve/eqcurve_coupler.cpp index 207d63a..2a599ac 100644 --- a/src/reactmicp/equilibrium_curve/eqcurve_coupler.cpp +++ b/src/reactmicp/equilibrium_curve/eqcurve_coupler.cpp @@ -1,106 +1,109 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "eqcurve_coupler.hpp" #include "dfpm/meshes/mesh1d.hpp" #include "dfpm/1dtransport/diffusion_parameters.hpp" #include "dfpmsolver/parabolic_driver.hpp" namespace specmicp { namespace reactmicp { namespace eqcurve { EquilibriumCurveCoupler::EquilibriumCurveCoupler(Matrix& eq_curve, mesh::Mesh1DPtr the_mesh , dfpmsolver::ParabolicDriverOptions options): m_eqcurve(eq_curve), m_mesh(the_mesh), m_param(std::make_shared(m_mesh->nb_nodes())), m_aqueous_concentrations(the_mesh->nb_nodes()), m_solid_concentrations(the_mesh->nb_nodes()), m_transport_program(the_mesh, m_param, {0,}), m_transport_solver(m_transport_program) { m_transport_solver.get_options() = options; index_t last = m_eqcurve.last(); m_aqueous_concentrations(0) = m_eqcurve.totaq_concentration(last); m_solid_concentrations(0) = m_eqcurve.totsolid_concentration(last); m_param->porosity(0) = m_eqcurve.porosity(last); m_param->diffusion_coefficient(0) = m_eqcurve.diffusion_coefficient(last); index_t first = m_eqcurve.first(); for (index_t node=1; nodenb_nodes(); ++node) { m_aqueous_concentrations(node) = m_eqcurve.totaq_concentration(first); m_solid_concentrations(node) = m_eqcurve.totsolid_concentration(first); m_param->porosity(node) = m_eqcurve.porosity(first); m_param->diffusion_coefficient(node) = m_eqcurve.diffusion_coefficient(first); } } void EquilibriumCurveCoupler::run_step(scalar_t timestep) { dfpmsolver::ParabolicDriverReturnCode retcode = m_transport_solver.solve_timestep(timestep, m_aqueous_concentrations); if (retcode <= dfpmsolver::ParabolicDriverReturnCode::NotConvergedYet) { throw std::runtime_error("Cannot solve the transport problem, retcode : "+std::to_string((int) retcode)); } chemistry_step(); } void EquilibriumCurveCoupler::chemistry_step() { for (index_t node=1; nodenb_nodes(); ++node) { index_t index = m_eqcurve.find_point(m_solid_concentrations(node)); //std::cout << index << std::endl; scalar_t ceq = m_eqcurve.totaq_concentration(index); //std::cout << m_solid_concentrations(node) << " - diff : " << m_eqcurve.porosity(index)*(ceq-m_aqueous_concentrations(node)) << std::endl; m_solid_concentrations(node) -= std::min( m_solid_concentrations(node), m_eqcurve.porosity(index)*(ceq-m_aqueous_concentrations(node))); m_aqueous_concentrations(node) = ceq; // ###FIXME -> locate node using previous guess index = m_eqcurve.find_point(m_solid_concentrations(node)); m_param->porosity(node) = m_eqcurve.porosity(index); m_param->diffusion_coefficient(node)= m_eqcurve.diffusion_coefficient(index); } } } // end namespace eqcurve } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/equilibrium_curve/eqcurve_coupler.hpp b/src/reactmicp/equilibrium_curve/eqcurve_coupler.hpp index a1be80a..9f0b118 100644 --- a/src/reactmicp/equilibrium_curve/eqcurve_coupler.hpp +++ b/src/reactmicp/equilibrium_curve/eqcurve_coupler.hpp @@ -1,81 +1,84 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_EQCURVECOUPLER_HPP #define SPECMICP_REACTMICP_EQCURVECOUPLER_HPP #include "eqcurve_extractor.hpp" #include "dfpm/meshes/mesh1dfwd.hpp" #include "dfpm/1dtransport/diffusion.hpp" #include "dfpmsolver/parabolic_driver.hpp" namespace specmicp { namespace dfpm { class SaturatedDiffusion1DParameters; } // end namespace dfpm namespace reactmicp { namespace eqcurve { class EquilibriumCurveCoupler { public: EquilibriumCurveCoupler(Matrix& eq_curve, mesh::Mesh1DPtr the_mesh, dfpmsolver::ParabolicDriverOptions options ); void run_step(scalar_t timestep); Vector& solid_concentrations() {return m_solid_concentrations;} Vector& aqueous_concentrations() {return m_aqueous_concentrations;} void chemistry_step(); private: EquilibriumCurveExtractor m_eqcurve; mesh::Mesh1DPtr m_mesh; std::shared_ptr m_param; Vector m_aqueous_concentrations; Vector m_solid_concentrations; dfpm::SaturatedDiffusion1D m_transport_program; dfpmsolver::ParabolicDriver m_transport_solver; }; } // end namespace eqcurve } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_EQCURVECOUPLER_HPP diff --git a/src/reactmicp/equilibrium_curve/eqcurve_extractor.cpp b/src/reactmicp/equilibrium_curve/eqcurve_extractor.cpp index 92d4a8d..549deb0 100644 --- a/src/reactmicp/equilibrium_curve/eqcurve_extractor.cpp +++ b/src/reactmicp/equilibrium_curve/eqcurve_extractor.cpp @@ -1,95 +1,98 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "eqcurve_extractor.hpp" #include namespace specmicp { namespace reactmicp { namespace eqcurve { index_t EquilibriumCurveExtractor::find_point(scalar_t x) { index_t index; const index_t size = m_eqcurve.rows(); index_t lower_index = 0; index_t upper_index = size+1; while (upper_index - lower_index > 1) { index = (upper_index + lower_index) /2; if ((x >= xs_offset(index)) == is_increasing()) lower_index = index; else upper_index = index; } if (x == xs_offset(1)) index = 0; else if (x == xs_offset(size)) index = size-1; else index = std::max((specmicp::index_t) 0, lower_index-1); return index; } scalar_t EquilibriumCurveExtractor::interpolate(index_t index, scalar_t x, index_t col) { // limit if (is_increasing()) { if (x <= m_eqcurve(first(), 0)) return m_eqcurve(first(), col); else if (x >= m_eqcurve(last(), 0)) return m_eqcurve(last(), col); } else { if (x >= m_eqcurve(first(), 0)) return m_eqcurve(first(), col); else if (x <= m_eqcurve(last(), 0)) return m_eqcurve(last(), col); } scalar_t y; const scalar_t diff = slope(index, col); y = m_eqcurve(index, col) + diff*(m_eqcurve(index+1,0)-x); return y; } scalar_t EquilibriumCurveExtractor::slope(index_t index, index_t col) { if (index == last()) return (m_eqcurve(index-1,col)-m_eqcurve(index,col))/(m_eqcurve(index-1,0)-m_eqcurve(index,0)); return (m_eqcurve(index+1,col)-m_eqcurve(index,col))/(m_eqcurve(index+1,0)-m_eqcurve(index,0)); } } // end namespace eqcurve } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/equilibrium_curve/eqcurve_extractor.hpp b/src/reactmicp/equilibrium_curve/eqcurve_extractor.hpp index 6134a69..a525bc2 100644 --- a/src/reactmicp/equilibrium_curve/eqcurve_extractor.hpp +++ b/src/reactmicp/equilibrium_curve/eqcurve_extractor.hpp @@ -1,96 +1,99 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_EQCURVEEXTRACTOR_HPP #define SPECMICP_REACTMICP_EQCURVEEXTRACTOR_HPP #include "common.hpp" namespace specmicp { namespace reactmicp { namespace eqcurve { class EquilibriumCurveExtractor { public: EquilibriumCurveExtractor(const Matrix& eq_curve): m_eqcurve(eq_curve) { m_is_increasing = (xs_offset(m_eqcurve.rows()) >= xs_offset(1)); } EquilibriumCurveExtractor(Matrix&& eq_curve): m_eqcurve(eq_curve) { m_is_increasing = (xs_offset(m_eqcurve.rows()) >= xs_offset(1)); } index_t find_point(scalar_t x); index_t first() {return 0;} index_t last() {return m_eqcurve.rows()-1;} bool is_increasing() {return m_is_increasing;} scalar_t totsolid_concentration(index_t index) { return m_eqcurve(index, 0); } scalar_t totaq_concentration(index_t index) { return m_eqcurve(index, 1); } scalar_t porosity(index_t index) { return m_eqcurve(index, 2); } scalar_t diffusion_coefficient(index_t index) { return m_eqcurve(index, 3); } scalar_t interpolate(index_t index, scalar_t x, index_t col); scalar_t slope(index_t index, index_t col); private: scalar_t xs_offset(index_t offset_index) { return m_eqcurve(offset_index-1, 0); } Matrix m_eqcurve; bool m_is_increasing; }; } // end namespace eqcurve } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_EQCURVEEXTRACTOR_HPP diff --git a/src/reactmicp/equilibrium_curve/eqcurve_solid_transport.cpp b/src/reactmicp/equilibrium_curve/eqcurve_solid_transport.cpp index aa97bf4..32b7a0e 100644 --- a/src/reactmicp/equilibrium_curve/eqcurve_solid_transport.cpp +++ b/src/reactmicp/equilibrium_curve/eqcurve_solid_transport.cpp @@ -1,262 +1,265 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "eqcurve_solid_transport.hpp" #include "dfpm/meshes/mesh1d.hpp" #include namespace specmicp { namespace reactmicp { namespace eqcurve { // SolidDiffusion:: SolidDiffusion::SolidDiffusion( mesh::Mesh1DPtr the_mesh, const Matrix& eq_curve, std::vector list_bcs ): m_tot_ndf(the_mesh->nb_nodes()), m_mesh(the_mesh), m_eqcurve(eq_curve), m_internal_flow(Vector::Zero(m_tot_ndf)), m_external_flow(Vector::Zero(m_tot_ndf)), m_in_jac(false) { number_equations(list_bcs); } void SolidDiffusion::number_equations(std::vector list_bcs) { m_id_equations = Eigen::VectorXi::Zero(m_tot_ndf); for (auto it=list_bcs.begin(); it!=list_bcs.end(); ++it) { m_id_equations(*it) = no_equation; } index_t neq = 0; for (index_t node: m_mesh->range_nodes()) { if (m_id_equations(node) == no_equation) continue; m_id_equations(node) = neq; ++ neq; } m_neq = neq; } void SolidDiffusion::compute_residuals( const Vector& displacement, const Vector& velocity, Vector& residual ) { m_internal_flow.setZero(); residual.resize(get_neq()); residual.setZero(); for (index_t element: m_mesh->range_elements()) { Vector elem_residuals(2); elem_residuals.setZero(); element_residuals(element, displacement, velocity, elem_residuals); for (index_t enode: m_mesh->range_nen()) { const index_t id_eq = id_equation(m_mesh->get_node(element, enode)); if (id_eq == no_equation) continue; residual(id_eq) += elem_residuals(enode); } } //std::cout << "residual : " << std::endl << residual << std::endl; //std::cout << "flow : " << std::endl << m_internal_flow << std::endl; } void SolidDiffusion::element_residuals( index_t element, const Vector& displacement, const Vector& velocity, Vector& elem_residuals ) { Eigen::Matrix jacob; Eigen::Matrix evelocity, econc; //scalar_t mass_coeff = -(m_mesh->get_volume_element(element)/2.0); const index_t node_0 = m_mesh->get_node(element, 0); const index_t node_1 = m_mesh->get_node(element, 1); const scalar_t mass_coeff_0 = m_mesh->get_volume_cell_element(element, 0); const scalar_t mass_coeff_1 = m_mesh->get_volume_cell_element(element, 1); const scalar_t sc_0 = displacement(node_0); const scalar_t sc_1 = displacement(node_1); const index_t index_0 = m_eqcurve.find_point(sc_0); const index_t index_1 = m_eqcurve.find_point(sc_1); //std::cout << element << " # " << index_0 << " - " << index_1 << std::endl; const scalar_t cc_0 = m_eqcurve.interpolate(index_0, sc_0, 1); //std::max(m_eqcurve.totaq_concentration(m_eqcurve.last()), m_eqcurve.interpolate(index_0, sc_0, 1)); const scalar_t cc_1 = m_eqcurve.interpolate(index_1, sc_1, 1); //std::max(m_eqcurve.totaq_concentration(m_eqcurve.last()), m_eqcurve.interpolate(index_1, sc_1, 1)); const scalar_t porosity_0 = m_eqcurve.interpolate(index_0, sc_0, 2); const scalar_t porosity_1 = m_eqcurve.interpolate(index_1, sc_1, 2); //const scalar_t diffcoeff_0 = m_eqcurve.interpolate(index_0, sc_0, 3); //const scalar_t diffcoeff_1 = m_eqcurve.interpolate(index_1, sc_1, 3); const scalar_t porosity = ( porosity_0 + porosity_1 )/2.0; const scalar_t diff_coeff = porosity>0.92?2.219e-5:1e4*std::exp(9.95*porosity-29.08); // const scalar_t diff_coeff = 1.0/(0.5/diffcoeff_0 + // 0.5/diffcoeff_1); scalar_t flux_coeff = ( m_mesh->get_face_area(element) / m_mesh->get_dx(element) //* porosity * diff_coeff ); // if (m_eqcurve.slope(index_1, 1) != 0) // { // std::cout << element << " # " << m_eqcurve.slope(index_0, 1) << " - " << m_eqcurve.slope(index_0, 2) // << " # " << m_eqcurve.slope(index_1, 1) << " - " << m_eqcurve.slope(index_1, 2) << std::endl; // } evelocity << (+ m_eqcurve.slope(index_0, 1)*porosity_0 + m_eqcurve.slope(index_0, 2)*cc_0 + 1.0)*mass_coeff_0*velocity(node_0), (+ m_eqcurve.slope(index_1, 1)*porosity_1 + m_eqcurve.slope(index_1, 2)*cc_1 + 1.0)*mass_coeff_1*velocity(node_1); jacob << 1.0, -1.0, -1.0, 1.0; jacob *= flux_coeff; econc << cc_0, cc_1; // if (element == 0) // std::cout << econc << std::endl; elem_residuals += jacob*econc; m_internal_flow(node_0) += elem_residuals(0); m_internal_flow(node_1) += elem_residuals(1); elem_residuals += evelocity; // for (index_t en: m_mesh->range_nen()) // { // elem_residuals(en) += evelocity(en); // elem_residuals(en) += (m_mesh->get_volume_element(element)/2.0 // *external_flow(m_mesh->get_node(element, en))); // } } void SolidDiffusion::compute_jacobian( Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian, scalar_t alphadt ) { m_in_jac = true; dfpm::list_triplet_t jacob; const index_t estimation = m_mesh->nb_nodes()*(m_mesh->nen); jacob.reserve(estimation); for (index_t element: m_mesh->range_elements()) { element_jacobian(element, displacement, velocity, jacob, alphadt); } jacobian = Eigen::SparseMatrix(get_neq(), get_neq()); jacobian.setFromTriplets(jacob.begin(), jacob.end()); m_in_jac = false; } void SolidDiffusion::element_jacobian( index_t element, Vector& displacement, Vector& velocity, dfpm::list_triplet_t& jacobian, scalar_t alphadt) { Eigen::VectorXd element_residual_orig(Eigen::VectorXd::Zero(2)); element_residuals(element, displacement, velocity, element_residual_orig); for (index_t en: m_mesh->range_nen()) { Eigen::VectorXd element_residual(Eigen::VectorXd::Zero(2)); const index_t node = m_mesh->get_node(element, en); const index_t dof = node; const index_t idc = id_equation(dof); if (idc == no_equation) continue; const scalar_t tmp_v = velocity(dof); const scalar_t tmp_d = displacement(dof); scalar_t h = eps_jacobian*std::abs(tmp_v); if (h < 1e-6) h = eps_jacobian; velocity(dof) = tmp_v + h; h = velocity(dof) - tmp_v; displacement(dof) = tmp_d + alphadt*h; element_residuals(element, displacement, velocity, element_residual); velocity(dof) = tmp_v; displacement(dof) = tmp_d; for (index_t enr: m_mesh->range_nen()) { const index_t noder = m_mesh->get_node(element, enr); const index_t idr = id_equation(noder); if (idr == no_equation) continue; jacobian.push_back(dfpm::triplet_t(idr, idc, (element_residual(enr) - element_residual_orig(enr))/h)); } } } void SolidDiffusion::update_solution(const Vector &update, scalar_t lambda, scalar_t alpha_dt, Vector &predictor, Vector &displacement, Vector &velocity ) { for (index_t node: m_mesh->range_nodes()) { const index_t id = id_equation(node); if (id == no_equation) continue; velocity(node) += lambda*update(id); } displacement = predictor + alpha_dt*velocity; } } // end namespace eqcurve } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/equilibrium_curve/eqcurve_solid_transport.hpp b/src/reactmicp/equilibrium_curve/eqcurve_solid_transport.hpp index 23234fa..7766bb0 100644 --- a/src/reactmicp/equilibrium_curve/eqcurve_solid_transport.hpp +++ b/src/reactmicp/equilibrium_curve/eqcurve_solid_transport.hpp @@ -1,140 +1,143 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_EQCURVE_SOLIDTRANSPORT_HPP #define SPECMICP_REACTMICP_EQCURVE_SOLIDTRANSPORT_HPP #include #include "common.hpp" #include "dfpm/types.hpp" #include "dfpmsolver/parabolic_program.hpp" #include "dfpm/meshes/mesh1dfwd.hpp" #include "eqcurve_extractor.hpp" namespace specmicp { namespace reactmicp { namespace eqcurve { class SolidDiffusion: public dfpmsolver::ParabolicProgram { public: SolidDiffusion( mesh::Mesh1DPtr the_mesh, const Matrix& eqcurve, std::vector list_bcs ); //! \brief Return the number of equations index_t get_neq() const {return m_neq;} //! \brief Return the number of degrees of freedom per node index_t get_ndf() const {return 1;} //! \brief Return the total number of degrees of freedom index_t get_tot_ndf() const {return m_tot_ndf;} //! \brief Return the id of the equation corresponding to the degree of freedom 'id_dof' //! //! Return 'no_equation' if no equation exist index_t id_equation(index_t id_dof) const {return m_id_equations(id_dof);} void element_residuals(index_t element, const Vector& displacement, const Vector& velocity, Vector& element_residual ); //! \brief Compute the residuals void compute_residuals(const Vector& displacement, const Vector& velocity, Vector& residual ); //! \brief Compute the jacobian void compute_jacobian(Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian, scalar_t alphadt ); void element_jacobian( index_t element, Vector& displacement, Vector& velocity, dfpm::list_triplet_t& jacobian, scalar_t alphadt); //! \brief Update the solutions void update_solution(const Vector& update, scalar_t lambda, scalar_t alpha_dt, Vector& predictor, Vector& displacement, Vector& velocity); //! \brief Apply boundary conditions to the velocity vector //! //! by default do nothing. void apply_bc(scalar_t dt, const Vector& displacement, Vector& velocity) {} //! \brief Return the value of the external flow for dof 'id_dof' scalar_t external_flow(index_t id_dof) const {return m_external_flow(id_dof);} //! \brief Return a reference to the value of the external flow for dof 'id_dof' scalar_t& external_flow(index_t id_dof) {return m_external_flow(id_dof);} //! \brief Return a reference to the vector of external flow Vector& external_flow() {return m_external_flow;} private: void number_equations(std::vector list_bcs); index_t m_tot_ndf; index_t m_neq; Eigen::VectorXi m_id_equations; mesh::Mesh1DPtr m_mesh; EquilibriumCurveExtractor m_eqcurve; Vector m_internal_flow; Vector m_external_flow; bool m_in_jac; }; } // end namespace eqcurve } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_EQCURVE_SOLIDTRANSPORT_HPP diff --git a/src/reactmicp/solver/reactive_transport_solver.cpp b/src/reactmicp/solver/reactive_transport_solver.cpp index 4a7258f..bff2409 100644 --- a/src/reactmicp/solver/reactive_transport_solver.cpp +++ b/src/reactmicp/solver/reactive_transport_solver.cpp @@ -1,250 +1,253 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "reactive_transport_solver.hpp" #include "staggers_base/staggers_base.hpp" #include "utils/log.hpp" #include "utils/timer.hpp" namespace specmicp { namespace reactmicp { namespace solver { namespace internal { // This contains internal information for the reactive transport solver // It is used to check the convergence struct ReactiveTransportResiduals { index_t nb_iterations; scalar_t transport_residual_0; scalar_t transport_residuals; scalar_t update; ReactiveTransportResiduals(): nb_iterations(0), transport_residual_0(-1), transport_residuals(-1), update(-1) {} }; } // end namespace internal // ReactiveTransportSolver:: // Solve a timestep // // Attention : This function uses goto to handle return code and performance ReactiveTransportReturnCode ReactiveTransportSolver::solve_timestep( scalar_t timestep, VariablesBasePtr variables ) { // start the timer Timer tot_timer; tot_timer.start(); // initialization internal::ReactiveTransportResiduals residuals; reset_perfs(); get_perfs().timestep = timestep; // copy of variables // ? m_transport_stagger->initialize_timestep(timestep, variables); m_chemistry_stagger->initialize_timestep(timestep, variables); m_upscaling_stagger->initialize_timestep(timestep, variables); // residuals.transport_residual_0 = m_transport_stagger->get_residual_0(variables); ReactiveTransportReturnCode retcode = one_iteration(variables, residuals); // check for failure if (retcode < ReactiveTransportReturnCode::StaggerFailure) { ERROR << "Failed to solve the iteration, return code : " << (int) retcode; goto set_return; } retcode = check_convergence(variables, residuals, false); ++residuals.nb_iterations; // if sequential non-iterative algorithm if (get_options().is_snia()) { goto end; } // else while (retcode == ReactiveTransportReturnCode::NotConvergedYet) { retcode = one_iteration(variables, residuals); // check for failure if (retcode < ReactiveTransportReturnCode::StaggerFailure) { ERROR << "Failed to solve the iteration, return code : " << (int) retcode; goto set_return; } if (retcode != ReactiveTransportReturnCode::TransportBypass) retcode = check_convergence(variables, residuals, true); retcode = check_convergence(variables, residuals, false); ++residuals.nb_iterations; } // wrapup end: // upscaling, if needed if (not get_options().implicit_upscaling) { Timer timer; timer.start(); m_upscaling_stagger->restart_timestep(variables); timer.stop(); m_timer.upscaling_time += timer.elapsed_time(); } // record performance and return code set_return: tot_timer.stop(); get_perfs().total_time = tot_timer.elapsed_time(); get_perfs().nb_iterations = residuals.nb_iterations; get_perfs().return_code = retcode; get_perfs().residuals = residuals.transport_residuals/residuals.transport_residual_0; return retcode; } ReactiveTransportReturnCode ReactiveTransportSolver::one_iteration( VariablesBasePtr variables, internal::ReactiveTransportResiduals& residuals ) { Timer timer; bool bypass = false; // Transport // --------- timer.start(); StaggerReturnCode transport_ret_code = m_transport_stagger->restart_timestep(variables); if (transport_ret_code <= StaggerReturnCode::NotConvergedYet) { return ReactiveTransportReturnCode::TransportFailure; } if (transport_ret_code == StaggerReturnCode::ErrorMinimized) { bypass = true; } timer.stop(); const scalar_t ttime = timer.elapsed_time(); m_timer.transport_time += ttime; get_perfs().transport_time += ttime; // Chemistry // --------- timer.start(); StaggerReturnCode chemistry_ret_code = m_chemistry_stagger->restart_timestep(variables); if (chemistry_ret_code <= StaggerReturnCode::NotConvergedYet) { return ReactiveTransportReturnCode::ChemistryFailure; } timer.stop(); const scalar_t ctime = timer.elapsed_time(); m_timer.chemistry_time += ctime; get_perfs().chemistry_time += ctime; // Upscaling0 // --------- if (get_options().implicit_upscaling) { timer.start(); StaggerReturnCode upscaling_ret_code = m_upscaling_stagger->restart_timestep(variables); if (upscaling_ret_code <= StaggerReturnCode::NotConvergedYet) { return ReactiveTransportReturnCode::UpscalingFailure; } timer.stop(); m_timer.upscaling_time += timer.elapsed_time(); } // Final residuals // --------------- residuals.transport_residuals = m_transport_stagger->get_residual(variables); residuals.update = m_transport_stagger->get_update(variables); if (bypass) return ReactiveTransportReturnCode::TransportBypass; return ReactiveTransportReturnCode::NotConvergedYet; } // Check the convergence ReactiveTransportReturnCode ReactiveTransportSolver::check_convergence( VariablesBasePtr _, const internal::ReactiveTransportResiduals& residuals, bool bypass ) { const scalar_t relative_residual = residuals.transport_residuals/residuals.transport_residual_0; // Residual if (relative_residual < get_options().residuals_tolerance or residuals.transport_residuals < get_options().absolute_residuals_tolerance) { return ReactiveTransportReturnCode::ResidualMinimized; } // Step else if (residuals.update < get_options().step_tolerance) { if (relative_residual < get_options().good_enough_tolerance) { return ReactiveTransportReturnCode::ErrorMinimized; } else return ReactiveTransportReturnCode::StationaryPoint; } else if (bypass) { return ReactiveTransportReturnCode::TransportBypass; } // Number of iterations else if (residuals.nb_iterations >= get_options().maximum_iterations) { if (relative_residual < get_options().good_enough_tolerance) { return ReactiveTransportReturnCode::GoodEnough; } return ReactiveTransportReturnCode::MaximumIterationsReached; } return ReactiveTransportReturnCode::NotConvergedYet; } } // end namespace solver } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/solver/reactive_transport_solver.hpp b/src/reactmicp/solver/reactive_transport_solver.hpp index 24136aa..3e40400 100644 --- a/src/reactmicp/solver/reactive_transport_solver.hpp +++ b/src/reactmicp/solver/reactive_transport_solver.hpp @@ -1,155 +1,158 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_SOLVER_REACTIVETRANSPORTSOLVER_HPP #define SPECMICP_REACTMICP_SOLVER_REACTIVETRANSPORTSOLVER_HPP //! \file reactive_transport_solver.hpp The reactive transport solver //! \namespace specmicp::reactmicp::solver Namespace containing the algorithms for the reactive transport solver #include "common.hpp" #include #include "reactive_transport_solver_structs.hpp" #include "utils/options_handler.hpp" #include "utils/perfs_handler.hpp" // forward declarations // ==================== namespace specmicp { namespace reactmicp { namespace solver { class VariablesBase; using VariablesBasePtr = std::shared_ptr; class TransportStaggerBase; class ChemistryStaggerBase; class UpscalingStaggerBase; using TransportStaggerPtr = std::shared_ptr; using ChemistryStaggerPtr = std::shared_ptr; using UpscalingStaggerPtr = std::shared_ptr; namespace internal { struct ReactiveTransportResiduals; } // end namespace internal } // end namespace solver } // end namespace reactmicp } // end namespace specmicp // Reactive Transport Solver // ========================= namespace specmicp { namespace reactmicp { namespace solver { //! \brief The reactive transport solver //! //! This class solves a reactive transport problem. //! The details of the problem are implemented in the staggers. //! //! There is three staggers : //! - The transport stagger //! - The chemistry stagger //! - The upscaling stagger //! //! The transport stagger also implements the residuals used to checked the convergence. //! //! This algorithm do not update, modify the variables. //! The details must be implemented in the staggers. //! The variables shared by the algorithm is a shared_ptr to the abstract base class specmicp::reactmicp::solver::VariablesBase //! To be useful, this variable must be casted to the true class in the staggers. class ReactiveTransportSolver: public OptionsHandler, public PerformanceHandler { public: //! \brief Build a reactive transport //! //! \param transport_stagger shared_ptr to a transport stagger //! \param chemistry_stagger shared_ptr to a chemistry stagger //! \param upscaling_stagger shared_ptr to an upscaling stagger ReactiveTransportSolver( TransportStaggerPtr transport_stagger, ChemistryStaggerPtr chemistry_stagger, UpscalingStaggerPtr upscaling_stagger ): m_transport_stagger(transport_stagger), m_chemistry_stagger(chemistry_stagger), m_upscaling_stagger(upscaling_stagger) {} //! \brief Solve a timestep //! //! \param timestep The duration of the timestep //! \param variables shared_ptr to the variables ReactiveTransportReturnCode solve_timestep( scalar_t timestep, VariablesBasePtr variables ); //! \brief Return the timer ReactiveTransportTimer& get_timer() {return m_timer;} private: // members //! \brief One iteration inside the timestep //! //! \param variables shared_ptr to the variables //! \param residuals struct containing the residuals information ReactiveTransportReturnCode one_iteration( VariablesBasePtr variables, internal::ReactiveTransportResiduals& residuals ); //! \brief Check the convergence //! //! \param variables shared_ptr to the variables //! \param residuals struct containing the residuals information ReactiveTransportReturnCode check_convergence( VariablesBasePtr variables, const internal::ReactiveTransportResiduals& residuals, bool bypass ); private: // attributes TransportStaggerPtr m_transport_stagger; //!< The transport stagger ChemistryStaggerPtr m_chemistry_stagger; //!< The chemistry stagger UpscalingStaggerPtr m_upscaling_stagger; //!< The upscaling stagger ReactiveTransportTimer m_timer; }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_REACTIVETRANSPORTSOLVER_HPP diff --git a/src/reactmicp/solver/reactive_transport_solver_structs.hpp b/src/reactmicp/solver/reactive_transport_solver_structs.hpp index 0c36772..5e96a0a 100644 --- a/src/reactmicp/solver/reactive_transport_solver_structs.hpp +++ b/src/reactmicp/solver/reactive_transport_solver_structs.hpp @@ -1,119 +1,122 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_SOLVER_REACTIVETRANSPORTSOLVERSTRUCTS_HPP #define SPECMICP_REACTMICP_SOLVER_REACTIVETRANSPORTSOLVERSTRUCTS_HPP #include "common.hpp" //! \file reactive_transport_solver_structs.hpp Structs used by the reactive transport solver namespace specmicp { namespace reactmicp { namespace solver { //! \brief Return codes used by the reactive transport solver enum class ReactiveTransportReturnCode { UpscalingFailure = -13, //!< Upscaling stagger has failed ChemistryFailure = -12, //!< Chemistry stagger has failed TransportFailure = -11, //!< Transport stagger has failed StaggerFailure = -10, //!< A stagger has failed MaximumIterationsReached = - 2, //!< Maximum number of fixed-point iterations is reached StationaryPoint = - 1, //!< The solver has reached a stationnary points NotConvergedYet = 0, //!< The solver has not converged yet ResidualMinimized = 1, //!< The residuals are minimized ErrorMinimized = 2, //!< The error is minimized (may indicate a stationnary point) GoodEnough = 3, //!< Good enough TransportBypass = 5, //!< Transport is minimized, no need to do iterations }; //! \brief Options used by the reactive transport solver struct ReactiveTransportOptions { scalar_t residuals_tolerance; //!< Relative tolerance for the residuals scalar_t absolute_residuals_tolerance; //!< Absolute tolerance for the residuals scalar_t step_tolerance; //!< Absolute tolerance for the step scalar_t good_enough_tolerance; //!< Relative tolerance to detect a stationnary point index_t maximum_iterations; //!< Maximum number of iterations allowed bool implicit_upscaling; //!< When true, the upscaling problem is solved at each iteration //! \brief Use a Sequential Non-iterative Algorithm void set_snia() {maximum_iterations = 1;} //! \brief Return true if the problem is solved using a SNIA bool is_snia() {return maximum_iterations <= 1;} ReactiveTransportOptions(): residuals_tolerance(1e-4), absolute_residuals_tolerance(1e-16), step_tolerance(1e-10), good_enough_tolerance(1e-2), maximum_iterations(100), implicit_upscaling(false) {} }; //! \brief Struct containing performance information //! //! This is valid for one timestep. struct ReactiveTransportPerformance { scalar_t timestep; //!< Timestep used index_t nb_iterations; //!< The number of fixed-point iterations for this timestep ReactiveTransportReturnCode return_code; //!< The return code of the timestep scalar_t residuals; //!< The norm of the residuals at the end of the timestep scalar_t total_time; //!< Time spent solving one timestep scalar_t transport_time; //!< Time spent solving the transport problem scalar_t chemistry_time; //!< Time spent solving the chemistry problem ReactiveTransportPerformance(): nb_iterations(0), return_code(ReactiveTransportReturnCode::NotConvergedYet), residuals(HUGE_VAL), total_time(0.0), transport_time(0.0), chemistry_time(0.0) {} }; //! \brief Struct containing the execution time of the staggers struct ReactiveTransportTimer { scalar_t transport_time; scalar_t chemistry_time; scalar_t upscaling_time; }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_REACTIVETRANSPORTSOLVERSTRUCTS_HPP diff --git a/src/reactmicp/solver/runner.cpp b/src/reactmicp/solver/runner.cpp index 1276b10..1f7b4de 100644 --- a/src/reactmicp/solver/runner.cpp +++ b/src/reactmicp/solver/runner.cpp @@ -1,105 +1,108 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "runner.hpp" #include "utils/io/reactive_transport.hpp" #include "utils/timer.hpp" #include #include "staggers_base/variables_base.hpp" namespace specmicp { namespace reactmicp { namespace solver { void ReactiveTransportRunner::run_until(scalar_t target, VariablesBasePtr variables) { Timer total_time; total_time.start(); m_timestepper.set_total_target(target); m_output_target = m_timestepper.get_total()+m_simulinfo.output_step; std::ofstream out_iter; if (m_simulinfo.print_iter_info) { out_iter.open(m_simulinfo.complete_filepath(std::string("iter"), std::string("dat"))); io::print_reactmicp_header(&out_iter); } scalar_t dt = m_timestepper.get_options().restart_timestep; ReactiveTransportReturnCode retcode = ReactiveTransportReturnCode::NotConvergedYet; while(retcode >= ReactiveTransportReturnCode::NotConvergedYet and m_timestepper.get_total() < m_timestepper.get_total_target()) { Timer step_timer; step_timer.start(); reactmicp::solver::ReactiveTransportReturnCode retcode = m_solver.solve_timestep(dt, variables); step_timer.stop(); if (m_simulinfo.print_iter_info) io::print_reactmicp_performance_long(&out_iter, m_cnt, m_timestepper.get_total()+dt, m_solver.get_perfs()); dt = m_timestepper.next_timestep(dt, retcode, m_solver.get_perfs().nb_iterations); if (retcode <= reactmicp::solver::ReactiveTransportReturnCode::NotConvergedYet) { dt = m_timestepper.get_options().restart_timestep; variables->reset_main_variables(); retcode = m_solver.solve_timestep(dt, variables); if (m_simulinfo.print_iter_info) io::print_reactmicp_performance_long(&out_iter, m_cnt, m_timestepper.get_total()+dt, m_solver.get_perfs()); dt = m_timestepper.next_timestep(dt, retcode, m_solver.get_perfs().nb_iterations); } ++m_cnt; // output if (m_timestepper.get_total() > m_output_target) { m_output_function(m_timestepper.get_total(), variables); m_output_target += m_simulinfo.output_step; } } total_time.stop(); if (m_simulinfo.print_iter_info) { io::print_reactmicp_end(&out_iter, total_time, get_timer()); out_iter.close(); } } } // end namespace solver } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/solver/runner.hpp b/src/reactmicp/solver/runner.hpp index a70d621..cc6c3a9 100644 --- a/src/reactmicp/solver/runner.hpp +++ b/src/reactmicp/solver/runner.hpp @@ -1,128 +1,131 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_SOLVER_RUNNER_HPP #define SPECMICP_REACTMICP_SOLVER_RUNNER_HPP #include "reactive_transport_solver.hpp" #include "timestepper.hpp" #include #include namespace specmicp { namespace reactmicp { namespace solver { //! \struct SimulationInformation //! \brief Information about the simulation struct SimulationInformation { std::string name; //!< Name of the simulation std::string output_prefix; //!< prefix for the output files bool print_iter_info{true}; //!< If true, print the iteration informations scalar_t output_step; //!< output step SimulationInformation(std::string name_simul, scalar_t outputstep): name(name_simul), output_prefix(name_simul+"_"), output_step(outputstep) {} std::string complete_filepath(const std::string& name, const std::string& suffix) const { return output_prefix+name+"."+suffix; } std::string complete_filepath(std::string&& name, std::string&& suffix) const { return output_prefix+name+"."+suffix; } }; using output_f = std::function; inline void dummy_output(scalar_t _, VariablesBasePtr __) {} class ReactiveTransportRunner { public: ReactiveTransportRunner(ReactiveTransportSolver& solver, scalar_t lower_dt_bound, scalar_t upper_dt_bound, const SimulationInformation& info): m_solver(solver), m_timestepper(lower_dt_bound, upper_dt_bound, 0, 2.0), m_simulinfo(info) { } void run_until(scalar_t target, VariablesBasePtr variables); void set_output_policy(output_f output_policy) { m_output_function = output_policy; } ReactiveTransportOptions& get_options() { return m_solver.get_options(); } TimestepperOptions& get_timestepper_options() { return m_timestepper.get_options(); } ReactiveTransportPerformance& get_perfs() { return m_solver.get_perfs(); } ReactiveTransportTimer& get_timer() { return m_solver.get_timer(); } private: index_t m_cnt{0}; ReactiveTransportSolver& m_solver; Timestepper m_timestepper; const SimulationInformation& m_simulinfo; output_f m_output_function{dummy_output}; scalar_t m_output_target; }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_RUNNER_HPP diff --git a/src/reactmicp/solver/staggers_base/chemistry_stagger_base.hpp b/src/reactmicp/solver/staggers_base/chemistry_stagger_base.hpp index e16444e..8205c55 100644 --- a/src/reactmicp/solver/staggers_base/chemistry_stagger_base.hpp +++ b/src/reactmicp/solver/staggers_base/chemistry_stagger_base.hpp @@ -1,75 +1,78 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_SOLVER_CHEMISTRYSTAGGERBASE_HPP #define SPECMICP_REACTMICP_SOLVER_CHEMISTRYSTAGGERBASE_HPP //! \file chemistry_stagger_base.hpp The base class for a chemistry stagger // following file include main data types and forward declaration needed for a stagger #include "decl.inl" namespace specmicp { namespace reactmicp { namespace solver { //! \brief The base class for a transport stagger //! //! Implement the chemistry (equilibrium, kinetics, ...) in a derived class class ChemistryStaggerBase { public: virtual ~ChemistryStaggerBase() {} //! \brief Initialize the stagger at the beginning of the computation //! //! \param var a shared_ptr to the variables virtual void initialize(VariablesBasePtr var) {} //! \brief Initialize the stagger at the beginning of an iteration //! //! This is where the predictor can be saved, the first trivial iteration done, ... //! //! \param dt the duration of the timestep //! \param var a shared_ptr to the variables virtual void initialize_timestep(scalar_t dt, VariablesBasePtr var) = 0; //! \brief Solve the equation for the timestep //! //! \param var a shared_ptr to the variables virtual StaggerReturnCode restart_timestep(VariablesBasePtr var) = 0; }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_CHEMISTRYSTAGGERBASE_HPP diff --git a/src/reactmicp/solver/staggers_base/decl.inl b/src/reactmicp/solver/staggers_base/decl.inl index f893bb2..393caad 100644 --- a/src/reactmicp/solver/staggers_base/decl.inl +++ b/src/reactmicp/solver/staggers_base/decl.inl @@ -1,52 +1,55 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_SOLVER_DECL_INL #define SPECMICP_REACTMICP_SOLVER_DECL_INL //! \file decl.inl common declaration needed for the *stagger_base headers #include "common.hpp" #include namespace specmicp { namespace reactmicp { namespace solver { // forward declaration class VariablesBase; using VariablesBasePtr = std::shared_ptr; enum class StaggerReturnCode; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_DECL_INL diff --git a/src/reactmicp/solver/staggers_base/stagger_structs.hpp b/src/reactmicp/solver/staggers_base/stagger_structs.hpp index a655096..99f9dfb 100644 --- a/src/reactmicp/solver/staggers_base/stagger_structs.hpp +++ b/src/reactmicp/solver/staggers_base/stagger_structs.hpp @@ -1,58 +1,61 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_SOLVER_STAGGERSTRUCTS_HPP #define SPECMICP_REACTMICP_SOLVER_STAGGERSTRUCTS_HPP //! \file stagger_structs.hpp common structs for the staggers namespace specmicp { namespace reactmicp { namespace solver { //! \brief Return code error used by a stagger //! //! Success of the stagger should be tested as : //! return code > NotConvergedYet enum class StaggerReturnCode { LolThatsNotSupposedToHappen, //!< Mainly for debugging purposes UnknownError, //!< Generic error, when used, an entry in the log is necessary MaximumIterationsReached, //!< Maximum number of iterations reached in the code StationaryPoint, //!< Stagger is stuck in a Stationary point NotConvergedYet, //!< The stagger has not converged yet ResidualMinimized, //!< The residuals are minimized ErrorMinimized //!< The error is minimized }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_STAGGERSTRUCTS_HPP diff --git a/src/reactmicp/solver/staggers_base/staggers_base.hpp b/src/reactmicp/solver/staggers_base/staggers_base.hpp index 6e26ff0..b8d2623 100644 --- a/src/reactmicp/solver/staggers_base/staggers_base.hpp +++ b/src/reactmicp/solver/staggers_base/staggers_base.hpp @@ -1,36 +1,39 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ //! \file staggers_base.hpp Include headers of the staggers base directory #include "variables_base.hpp" #include "transport_stagger_base.hpp" #include "chemistry_stagger_base.hpp" #include "upscaling_stagger_base.hpp" #include "stagger_structs.hpp" diff --git a/src/reactmicp/solver/staggers_base/transport_stagger_base.hpp b/src/reactmicp/solver/staggers_base/transport_stagger_base.hpp index 0ed203d..e335b22 100644 --- a/src/reactmicp/solver/staggers_base/transport_stagger_base.hpp +++ b/src/reactmicp/solver/staggers_base/transport_stagger_base.hpp @@ -1,88 +1,91 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_SOLVER_TRANSPORTSTAGGERBASE_HPP #define SPECMICP_REACTMICP_SOLVER_TRANSPORTSTAGGERBASE_HPP //! \file transport_stagger_base.hpp The base class for the transport stagger // following file include main data types and forward declaration needed for a stagger #include "decl.inl" namespace specmicp { namespace reactmicp { namespace solver { //! \brief The base class for a transport stagger //! class TransportStaggerBase { public: virtual ~TransportStaggerBase() {} //! \brief Initialize the stagger at the beginning of the computation //! //! \param var shared_ptr to the variables virtual void initialize(VariablesBasePtr var) {} //! \brief Initialize the stagger at the beginning of an iteration //! //! This is where the first residual may be computed, the predictor saved, ... //! \param dt the duration of the timestep //! \param var shared_ptr to the variables virtual void initialize_timestep(scalar_t dt, VariablesBasePtr var) = 0; //! \brief Solve the equation for the timetep //! //! \param var shared_ptr to the variables virtual StaggerReturnCode restart_timestep(VariablesBasePtr var) = 0; //! \brief Compute the residuals norm //! //! \param var shared_ptr to the variables virtual scalar_t get_residual(VariablesBasePtr var) = 0; //! \brief Compute the residuals norm //! //! \param var shared_ptr to the variables virtual scalar_t get_residual_0(VariablesBasePtr var) = 0; //! \brief Obtain the norm of the step size //! //! This is used to check if the algorithm has reach a stationary points. //! It should look like : return main_variables.norm() //! //! \param var shared_ptr to the variables virtual scalar_t get_update(VariablesBasePtr var) = 0; }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_TRANSPORTSTAGGERBASE_HPP diff --git a/src/reactmicp/solver/staggers_base/upscaling_stagger_base.hpp b/src/reactmicp/solver/staggers_base/upscaling_stagger_base.hpp index 435d194..3c4c1de 100644 --- a/src/reactmicp/solver/staggers_base/upscaling_stagger_base.hpp +++ b/src/reactmicp/solver/staggers_base/upscaling_stagger_base.hpp @@ -1,73 +1,76 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_SOLVER_UPSCALINGSTAGGERBASE_HPP #define SPECMICP_REACTMICP_SOLVER_UPSCALINGSTAGGERBASE_HPP //! \file upscaling_stagger_base.hpp The base class for the upscaling stagger // following file include main data types and forward declaration needed for a stagger #include "decl.inl" namespace specmicp { namespace reactmicp { namespace solver { //! \brief The base class for an upscaling stagger //! class UpscalingStaggerBase { public: virtual ~UpscalingStaggerBase() {} //! \brief Initialize the stagger at the beginning of the computation //! //! \param var a shared_ptr to the variables virtual void initialize(VariablesBasePtr var) {} //! \brief Initialize the stagger at the beginning of an iteration //! //! This is where the predictor can be saved, the first trivial iteration done, ... //! //! \param dt the duration of the timestep //! \param var a shared_ptr to the variables virtual void initialize_timestep(scalar_t dt, VariablesBasePtr var) = 0; //! \brief Solve the equation for the timestep //! //! \param var a shared_ptr to the variables virtual StaggerReturnCode restart_timestep(VariablesBasePtr var) = 0; }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_UPSCALINGSTAGGERBASE_HPP diff --git a/src/reactmicp/solver/staggers_base/variables_base.hpp b/src/reactmicp/solver/staggers_base/variables_base.hpp index 13eec40..6369be9 100644 --- a/src/reactmicp/solver/staggers_base/variables_base.hpp +++ b/src/reactmicp/solver/staggers_base/variables_base.hpp @@ -1,55 +1,58 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_SOLVER_VARIABLESBASE_HPP #define SPECMICP_REACTMICP_SOLVER_VARIABLESBASE_HPP //! \file variables_base.hpp Base class for a reactive transport variables namespace specmicp { namespace reactmicp { namespace solver { //! \brief Variables base class //! //! This is just for polymorphism, implementations is left to the user. class VariablesBase { public: virtual ~VariablesBase() {} //! \brief Reset the variables to restart a computation in case of failure virtual void reset_main_variables() = 0; }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_VARIABLESBASE_HPP diff --git a/src/reactmicp/solver/timestepper.cpp b/src/reactmicp/solver/timestepper.cpp index 8151c51..63ed723 100644 --- a/src/reactmicp/solver/timestepper.cpp +++ b/src/reactmicp/solver/timestepper.cpp @@ -1,94 +1,97 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "timestepper.hpp" #include "reactive_transport_solver_structs.hpp" namespace specmicp { namespace reactmicp { namespace solver { scalar_t Timestepper::next_timestep( scalar_t dt_done, ReactiveTransportReturnCode return_code, index_t nb_iterations ) { if (return_code <= ReactiveTransportReturnCode::NotConvergedYet) { return get_options().decrease_failure*dt_done; } // previous timestep is correct m_total += dt_done; m_average.add_point(nb_iterations); scalar_t proposed_dt = dt_done; // If the error is minimized we increase the timestep if (return_code == ReactiveTransportReturnCode::ErrorMinimized) { proposed_dt *= get_options().increase_error_minimization; } else // Increase or decrease the timestep to reach the number of iteration target range { if (m_average.current_value() <= get_options().iteration_lower_target) { proposed_dt *= get_options().increase_factor; } else if (m_average.current_value() > get_options().iteration_upper_target) { proposed_dt *= get_options().decrease_factor; } } // Check that the total target is not exceeded if (m_total + proposed_dt > m_total_target) { proposed_dt = m_total_target - m_total; } // Check that the timestep is inside the bounds if (proposed_dt < get_options().lower_bound) { proposed_dt = get_options().lower_bound; } else if (proposed_dt > get_options().upper_bound) { proposed_dt = get_options().upper_bound; } return proposed_dt; } } // end namespace solver } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/solver/timestepper.hpp b/src/reactmicp/solver/timestepper.hpp index a3ab2bb..bccbda8 100644 --- a/src/reactmicp/solver/timestepper.hpp +++ b/src/reactmicp/solver/timestepper.hpp @@ -1,116 +1,119 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_SOLVER_TIMESTEPPER_HPP #define SPECMICP_REACTMICP_SOLVER_TIMESTEPPER_HPP #include "utils/moving_average.hpp" #include "utils/options_handler.hpp" namespace specmicp { namespace reactmicp { namespace solver { // forward declaration enum class ReactiveTransportReturnCode; //! \brief Options for the timestepper struct TimestepperOptions { scalar_t lower_bound; //!< Lower bound for the timestep scalar_t upper_bound; //!< Upper bound for the timestep scalar_t restart_timestep; //!< Value used when restarting the problem scalar_t iteration_lower_target{1.01}; //!< Lower target for the number of iterations scalar_t iteration_upper_target{15.0}; //!< Upper target for the number of iterations scalar_t alpha_average{0.5}; //!< Parameter for the exponential moving average scalar_t decrease_failure{0.5}; //!< Reduction factor in case of failure scalar_t increase_error_minimization{1.3}; //!< Increase factor in case of error minimization scalar_t decrease_factor{0.75}; //!< Reduction factor to get the number of iterations inside the target scalar_t increase_factor{1.25}; //!< Increase factor to get the number of iterations inside the target TimestepperOptions(scalar_t dt_lower_bound, scalar_t dt_upper_bound): lower_bound(dt_lower_bound), upper_bound(dt_upper_bound), restart_timestep(dt_lower_bound) {} }; //! \brief Adaptative timestepper for the reactive transport solver class Timestepper: public OptionsHandler { public: //! \brief Constructor //! //! \param dt_lower_bound lower_bound for the timestep //! \param dt_upper_bound upper_bound for the timestep //! \param total_target total target time //! \param init_iterations initial iterations Timestepper(scalar_t dt_lower_bound, scalar_t dt_upper_bound, scalar_t total_target, scalar_t init_iterations ): OptionsHandler(dt_lower_bound, dt_upper_bound), m_total(0), m_total_target(total_target), m_average(0.5, init_iterations) { m_average.set_alpha(get_options().alpha_average); } //! \brief Return the total time scalar_t get_total() const {return m_total;} //! \brief Return the total target time scalar_t get_total_target() const {return m_total_target;} //! \brief Set the total target time void set_total_target(scalar_t total_target) {m_total_target = total_target;} void set_average_parameter(scalar_t alpha) { get_options().alpha_average = alpha; m_average.set_alpha(alpha); } //! obtain the next timestep scalar_t next_timestep(scalar_t dt_done, ReactiveTransportReturnCode return_code, index_t nb_iterations); private: scalar_t m_total; scalar_t m_total_target; utils::ExponentialMovingAverage m_average; }; } // end namespace solver } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SOLVER_TIMESTEPPER_HPP diff --git a/src/reactmicp/systems/saturated_react/equilibrium_stagger.cpp b/src/reactmicp/systems/saturated_react/equilibrium_stagger.cpp index e39e2a4..8cf04e3 100644 --- a/src/reactmicp/systems/saturated_react/equilibrium_stagger.cpp +++ b/src/reactmicp/systems/saturated_react/equilibrium_stagger.cpp @@ -1,171 +1,174 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "equilibrium_stagger.hpp" #include "variables.hpp" #include "specmicp/adimensional/adimensional_system_solver.hpp" #include "specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include "utils/log.hpp" #include "reactmicp/solver/staggers_base/stagger_structs.hpp" #ifdef SPECMICP_USE_OPENMP #include #endif // SPECMICP_USE_OPENMP namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { // EquilibriumStagger:: //! \brief Initialize the stagger at the beginning of an iteration void EquilibriumStagger::initialize_timestep(scalar_t dt, VariablesBasePtr var) { m_dt = dt; SaturatedVariablesPtr true_var = cast_var_from_base(var); // Initialize velocity using values from previous timestep for (index_t node=0; nodenb_nodes(); ++node) { if (true_var->is_fixed_composition(node)) continue; scalar_t alpha = 1.0; for (index_t component: true_var->get_database()->range_aqueous_component()) { alpha = std::max(alpha, 0.9*dt*true_var->solid_concentration(node, component, true_var->chemistry_rate()) /(true_var->solid_concentration(node, component, true_var->displacement())) ); } auto solid_velocity = true_var->velocity().segment( true_var->offset_node(node)+true_var->offset_solid_concentration(), true_var->nb_component()); auto solid_chemistry_rate = true_var->chemistry_rate().segment( true_var->offset_node(node)+true_var->offset_solid_concentration(), true_var->nb_component()); solid_velocity = 1/alpha * solid_chemistry_rate; } } //! \brief Solve the equation for the timestep solver::StaggerReturnCode EquilibriumStagger::restart_timestep(VariablesBasePtr var) { SaturatedVariablesPtr true_var = cast_var_from_base(var); int failed_chemistry = 0; #ifdef SPECMICP_USE_OPENMP #pragma omp parallel default(none) shared(true_var, failed_chemistry) { #pragma omp for schedule(dynamic, 5) for (index_t node=0; nodenb_nodes(); ++node) { // only solve if necessary if (true_var->is_fixed_composition(node) or failed_chemistry > 0) continue; const auto retcode = solve_one_node(node, true_var); if (retcode > 0) { ++failed_chemistry; } } } #else { for (index_t node=0; nodenb_nodes(); ++node) { if (true_var->is_fixed_composition(node)) continue; const auto retcode = solve_one_node(node, true_var); if (retcode > 0) { ++failed_chemistry; break; } } } #endif // SPECMICP_USE_OPENMP if (failed_chemistry > 0) return solver::StaggerReturnCode::UnknownError; return solver::StaggerReturnCode::ResidualMinimized; } //! int EquilibriumStagger::solve_one_node(index_t node, SaturatedVariablesPtr true_var) { AdimensionalSystemConstraints constraints(get_constraints(node)); constraints.total_concentrations = true_var->total_concentrations(node); AdimensionalSystemSolver adim_solver(true_var->get_database(), constraints, true_var->equilibrium_solution(node), m_options); Vector variables(true_var->equilibrium_solution(node).main_variables); micpsolver::MiCPPerformance perf = adim_solver.solve(variables); micpsolver::MiCPSolverReturnCode retcode = perf.return_code; if (retcode <= micpsolver::MiCPSolverReturnCode::NotConvergedYet) { ERROR << "Failed to solve chemistry problem at node " << node << ", return code = " << static_cast(retcode) << ", residual = " << perf.current_residual; ERROR << "Total concentration : \n" << constraints.total_concentrations; return 1; } true_var->equilibrium_solution(node) = adim_solver.get_raw_solution(variables); AdimensionalSystemSolutionExtractor extractor(true_var->equilibrium_solution(node), true_var->get_database(), m_options.units_set); for (index_t component=0; componentnb_component(); ++component) { const scalar_t c_aq = extractor.density_water()*extractor.total_aqueous_concentration(component); true_var->aqueous_concentration(node, component, true_var->displacement()) = c_aq; const scalar_t c_aq_0 = true_var->aqueous_concentration(node, component, true_var->predictor()); const scalar_t vel_aq = (c_aq - c_aq_0)/m_dt; true_var->aqueous_concentration(node, component, true_var->velocity()) = vel_aq; const scalar_t c_sol = extractor.total_immobile_concentration(component); true_var->solid_concentration(node, component, true_var->displacement()) = c_sol; const scalar_t c_sol_0 = true_var->solid_concentration(node, component, true_var->predictor()); const scalar_t vel_sol = (c_sol - c_sol_0)/m_dt; true_var->solid_concentration(node, component, true_var->velocity()) = vel_sol; true_var->solid_concentration(node, component, true_var->chemistry_rate()) = vel_sol; } return 0; } } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/systems/saturated_react/equilibrium_stagger.hpp b/src/reactmicp/systems/saturated_react/equilibrium_stagger.hpp index fc4df2f..830d6e2 100644 --- a/src/reactmicp/systems/saturated_react/equilibrium_stagger.hpp +++ b/src/reactmicp/systems/saturated_react/equilibrium_stagger.hpp @@ -1,99 +1,102 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_SYSTEMS_SATURATED_EQUILIBRIUMSTAGGER_HPP #define SPECMICP_REACTMICP_SYSTEMS_SATURATED_EQUILIBRIUMSTAGGER_HPP #include "reactmicp/solver/staggers_base/chemistry_stagger_base.hpp" #include "variablesfwd.hpp" #include "specmicp/adimensional/adimensional_system_solver_structs.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { using VariablesBasePtr = solver::VariablesBasePtr; //! \brief Solve the equilibrium problem class EquilibriumStagger: public solver::ChemistryStaggerBase { public: EquilibriumStagger(index_t nb_nodes, AdimensionalSystemConstraints constraints, AdimensionalSystemSolverOptions options): m_id_constraints(nb_nodes, 0), m_list_constraints({constraints,}), m_options(options) {} EquilibriumStagger( std::vector list_constraints, std::vector index_constraints, AdimensionalSystemSolverOptions options): m_id_constraints(index_constraints), m_list_constraints(list_constraints), m_options(options) {} //! \brief Initialize the stagger at the beginning of the computation void initialize(VariablesBasePtr var) {} //! \brief Initialize the stagger at the beginning of an iteration void initialize_timestep(scalar_t dt, VariablesBasePtr var) override; //! \brief Solve the equation for the timestep solver::StaggerReturnCode restart_timestep(VariablesBasePtr var) override; //! \brief Solve the speciation problem at one node int solve_one_node(index_t node, SaturatedVariablesPtr var); //! \brief Return the constraints for 'node' //! //! \param node Index of the node AdimensionalSystemConstraints& get_constraints(index_t node) { return m_list_constraints[m_id_constraints[node]]; } private: scalar_t m_dt; std::vector m_id_constraints; std::vector m_list_constraints; AdimensionalSystemSolverOptions m_options; }; } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SYSTEMS_SATURATED_EQUILIBRIUMSTAGGER_HPP diff --git a/src/reactmicp/systems/saturated_react/init_variables.cpp b/src/reactmicp/systems/saturated_react/init_variables.cpp index 8f69269..ca3edb4 100644 --- a/src/reactmicp/systems/saturated_react/init_variables.cpp +++ b/src/reactmicp/systems/saturated_react/init_variables.cpp @@ -1,115 +1,118 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "init_variables.hpp" #include "variables.hpp" #include "dfpm/meshes/mesh1d.hpp" #include "specmicp/adimensional/adimensional_system_solution_extractor.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { // SaturatedVariablesFactory:: SaturatedVariablesFactory::SaturatedVariablesFactory( mesh::Mesh1DPtr the_mesh, RawDatabasePtr the_database, units::UnitsSet the_units, const std::vector& list_fixed_nodes, const std::vector& list_initial_states, const std::vector& index_initial_state ): m_variable(std::make_shared(the_mesh, the_database)), m_database(the_database), nb_component(the_database->nb_component()), nb_nodes(the_mesh->nb_nodes()) { init_size(); set_fixed_nodes(list_fixed_nodes); init_chemistry(the_units, index_initial_state, list_initial_states); } void SaturatedVariablesFactory::init_size() { index_t main_ndf = nb_nodes*2*nb_component; m_variable->displacement() = Vector::Zero(main_ndf); m_variable->chemistry_rate() = Vector::Zero(main_ndf); m_variable->transport_rate() = Vector::Zero(main_ndf); m_variable->predictor() = Vector::Zero(main_ndf); m_variable->velocity() = Vector::Zero(main_ndf); m_variable->m_upscaling = Vector::Zero(m_variable->ndf_upscaling()*nb_nodes); } void SaturatedVariablesFactory::set_fixed_nodes(const std::vector& list_fixed_nodes) { m_variable->m_is_fixed_composition = std::vector(nb_nodes, false); for (index_t node: list_fixed_nodes) { m_variable->m_is_fixed_composition[node] = true; } } void SaturatedVariablesFactory::init_chemistry( units::UnitsSet the_units, const std::vector& index_initial_state, const std::vector& list_initial_states) { m_variable->m_equilibrium_solutions.reserve(nb_nodes); for (index_t node=0; nodem_equilibrium_solutions.push_back(list_initial_states[index_initial_state[node]]); AdimensionalSystemSolutionExtractor extractor(m_variable->m_equilibrium_solutions[node], m_database, the_units); scalar_t rho_w = extractor.density_water(); for (index_t component: m_database->range_component()) { m_variable->aqueous_concentration(node, component, m_variable->displacement()) = rho_w*extractor.total_aqueous_concentration(component); m_variable->solid_concentration(node, component, m_variable->displacement()) = extractor.total_immobile_concentration(component); } } } } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/systems/saturated_react/init_variables.hpp b/src/reactmicp/systems/saturated_react/init_variables.hpp index 6fad376..8443b90 100644 --- a/src/reactmicp/systems/saturated_react/init_variables.hpp +++ b/src/reactmicp/systems/saturated_react/init_variables.hpp @@ -1,97 +1,100 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_SYSTEMS_SATURATED_INITVARIABLES_HPP #define SPECMICP_REACTMICP_SYSTEMS_SATURATED_INITVARIABLES_HPP #include "variablesfwd.hpp" #include "dfpm/meshes/mesh1dfwd.hpp" #include "database.hpp" #include "specmicp/adimensional/adimensional_system_solution.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { //! \brief Initialize an instance of Saturated Variables class SaturatedVariablesFactory { public: SaturatedVariablesFactory( mesh::Mesh1DPtr the_mesh, RawDatabasePtr the_database, units::UnitsSet the_units, const std::vector& list_fixed_nodes, const std::vector& list_initial_states, const std::vector& index_initial_state ); //! \brief Initialize the main vectors void init_size(); //! \brief Initialize the BC void set_fixed_nodes(const std::vector& list_fixed_nodes); //! \brief Initialize the chemistry informations void init_chemistry( units::UnitsSet the_units, const std::vector& index_initial_state, const std::vector& list_initial_states); //! \brief Return the variables SaturatedVariablesPtr get_variable() {return m_variable;} private: SaturatedVariablesPtr m_variable; RawDatabasePtr m_database; index_t nb_component; index_t nb_nodes; }; //! \brief Initialise an instance of SaturatedVariables inline SaturatedVariablesPtr init_variables( mesh::Mesh1DPtr the_mesh, RawDatabasePtr the_database, units::UnitsSet the_units, const std::vector& list_fixed_nodes, const std::vector& list_initial_states, const std::vector& index_initial_state ) { SaturatedVariablesFactory factory(the_mesh, the_database, the_units, list_fixed_nodes, list_initial_states, index_initial_state); return factory.get_variable(); } } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SYSTEMS_SATURATED_INITVARIABLES_HPP diff --git a/src/reactmicp/systems/saturated_react/react_solver.cpp b/src/reactmicp/systems/saturated_react/react_solver.cpp index e8751fd..a0b7682 100644 --- a/src/reactmicp/systems/saturated_react/react_solver.cpp +++ b/src/reactmicp/systems/saturated_react/react_solver.cpp @@ -1,40 +1,43 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "react_solver.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/systems/saturated_react/react_solver.hpp b/src/reactmicp/systems/saturated_react/react_solver.hpp index f5a653b..83c7ac6 100644 --- a/src/reactmicp/systems/saturated_react/react_solver.hpp +++ b/src/reactmicp/systems/saturated_react/react_solver.hpp @@ -1,47 +1,50 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_SYSTEMS_SATURATED_REACTSOLVER_HPP #define SPECMICP_REACTMICP_SYSTEMS_SATURATED_REACTSOLVER_HPP namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SYSTEMS_SATURATED_REACTSOLVER_HPP diff --git a/src/reactmicp/systems/saturated_react/transport_program.cpp b/src/reactmicp/systems/saturated_react/transport_program.cpp index e219487..392d8a7 100644 --- a/src/reactmicp/systems/saturated_react/transport_program.cpp +++ b/src/reactmicp/systems/saturated_react/transport_program.cpp @@ -1,314 +1,317 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "transport_program.hpp" #include "dfpm/meshes/mesh1d.hpp" #include "variables.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { //class SaturatedDiffusion:: SaturatedDiffusion::SaturatedDiffusion(SaturatedVariablesPtr variables, std::vector list_fixed_nodes): m_ndf(2*variables->nb_component()), m_tot_ndf(2*variables->nb_component()*variables->get_mesh()->nb_nodes()), m_mesh(variables->get_mesh()), m_variables(variables), m_is_in_residual_computation(false) { number_equations(list_fixed_nodes, {}, {0, 1}); } SaturatedDiffusion::SaturatedDiffusion(SaturatedVariablesPtr variables, std::vector list_fixed_nodes, std::map list_slave_nodes, std::vector list_immobile_components): m_ndf(2*variables->nb_component()), m_tot_ndf(2*variables->nb_component()*variables->get_mesh()->nb_nodes()), m_mesh(variables->get_mesh()), m_variables(variables), m_is_in_residual_computation(false) { number_equations(list_fixed_nodes, list_slave_nodes, list_immobile_components); } void SaturatedDiffusion::number_equations(std::vector list_fixed_nodes, std::map list_slave_nodes, std::vector list_immobile_components) { m_ideq.resizeLike(m_variables->displacement()); m_ideq.setZero(); // flag fixed nodes for (index_t node: list_fixed_nodes) { for (index_t component=2; componentnb_component(); ++component) { m_ideq(m_variables->dof_aqueous_concentration(node, component)) = no_equation; } } // flag slaves nodes // we flag them by making their ideq more negative than no_equation for (auto slave_pair: list_slave_nodes) { for (index_t component=2; componentnb_component(); ++component) { m_ideq(m_variables->dof_aqueous_concentration(slave_pair.first, component)) = no_equation-1; } } // set equation numbers index_t neq = 0; for (index_t node=0; nodenb_nodes(); ++node) { for (index_t component: list_immobile_components) { m_ideq(m_variables->dof_aqueous_concentration(node, component)) = no_equation; m_ideq(m_variables->dof_aqueous_concentration(node, component)) = no_equation; } for (index_t component=0; componentnb_component(); ++component) { index_t dof = m_variables->dof_aqueous_concentration(node, component); if (m_ideq(dof) > no_equation) // attribute an equation number if it is NOT a slave nor a fixed node { m_ideq(dof) = neq; ++neq; } dof = m_variables->dof_solid_concentration(node, component); m_ideq(dof) = no_equation; } } // slave nodes // attribute the correct equation number for (auto slave_pair: list_slave_nodes) { for (index_t component=1; componentnb_component(); ++component) { m_ideq(m_variables->dof_aqueous_concentration(slave_pair.first, component)) = m_ideq(m_variables->dof_aqueous_concentration(slave_pair.second, component)); } } m_neq = neq; } void SaturatedDiffusion::compute_residuals( const Vector& displacement, const Vector& velocity, Vector& residual) { residual = Vector::Zero(get_neq()); m_is_in_residual_computation = true; for (index_t element: m_mesh->range_elements()) { for (index_t component=2; componentnb_component(); ++component) { Eigen::Vector2d element_residual; element_residual.setZero(); residuals_element_component(element, component, displacement, velocity, element_residual); for (index_t en=0; en<2; ++en) { const index_t node = m_mesh->get_node(element, en); const index_t id = m_ideq(m_variables->dof_aqueous_concentration(node, component)); if (id != no_equation) {residual(id) += element_residual(en);} } } } m_is_in_residual_computation = false; } void SaturatedDiffusion::residuals_element_component( index_t element, index_t component, const Vector& displacement, const Vector& velocity, Eigen::Vector2d& element_residual ) { const scalar_t mass_coeff_0 = -m_mesh->get_volume_cell_element(element, 0); const scalar_t mass_coeff_1 = -m_mesh->get_volume_cell_element(element, 1); const index_t node_0 = m_mesh->get_node(element, 0); const index_t node_1 = m_mesh->get_node(element, 1); const scalar_t diff_coeff = 1.0/(0.5/m_variables->diffusion_coefficient(node_0) + 0.5/m_variables->diffusion_coefficient(node_1)); scalar_t flux_coeff = -( m_mesh->get_face_area(element) / m_mesh->get_dx(element) * diff_coeff ) ; const index_t dof_0 = m_variables->dof_aqueous_concentration(node_0, component); const index_t dof_1 = m_variables->dof_aqueous_concentration(node_1, component); // diffusion scalar_t flux_diffusion = flux_coeff*(displacement(dof_0) - displacement(dof_1)); element_residual(0) = flux_diffusion; element_residual(1) = - flux_diffusion; // advection if (m_variables->fluid_velocity(element) != 0.0) { scalar_t flux_advection = (m_mesh->get_face_area(element)) *m_variables->fluid_velocity(element); if (m_variables->fluid_velocity(element) > 0) { flux_advection *= (displacement(dof_0) - displacement(dof_1)); element_residual(1) += flux_advection; } else { flux_advection *= (displacement(dof_1) - displacement(dof_0)); element_residual(0) -= flux_advection; } } if (m_is_in_residual_computation) { m_variables->aqueous_concentration(node_0, component, m_variables->transport_rate()) += element_residual(0); m_variables->aqueous_concentration(node_1, component, m_variables->transport_rate()) += element_residual(1); } // velocity element_residual(0) += mass_coeff_0*(velocity(dof_0)*m_variables->porosity(node_0) +m_variables->vel_porosity(node_0)*displacement(dof_0)); element_residual(1) += mass_coeff_1*(velocity(dof_1)*m_variables->porosity(node_1) + m_variables->vel_porosity(node_1)*displacement(dof_1)); // external rate element_residual(0) += mass_coeff_0*m_variables->solid_concentration(node_0, component, m_variables->chemistry_rate()); element_residual(1) += mass_coeff_1*m_variables->solid_concentration(node_1, component, m_variables->chemistry_rate()); } void SaturatedDiffusion::compute_jacobian( Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian, scalar_t alphadt ) { dfpm::list_triplet_t jacob; const index_t ncomp = m_variables->nb_component(); const index_t estimation = m_mesh->nb_nodes()*(ncomp*m_mesh->nen); jacob.reserve(estimation); for (index_t element: m_mesh->range_elements()) { jacobian_element(element, displacement, velocity, jacob, alphadt); } jacobian = Eigen::SparseMatrix(get_neq(), get_neq()); jacobian.setFromTriplets(jacob.begin(), jacob.end()); } void SaturatedDiffusion::jacobian_element( index_t element, Vector& displacement, Vector& velocity, dfpm::list_triplet_t& jacobian, scalar_t alphadt) { for (index_t component=1; componentnb_component(); ++component) { Eigen::Vector2d element_residual_orig(Eigen::Vector2d::Zero()); residuals_element_component(element, component, displacement, velocity, element_residual_orig); for (index_t en=0; en<2; ++en) { Eigen::Vector2d element_residual(Eigen::Vector2d::Zero()); const index_t node = m_mesh->get_node(element, en); const index_t dof = m_variables->dof_aqueous_concentration(node, component); const index_t idc = m_ideq(dof); if (idc == no_equation) continue; const scalar_t tmp_v = velocity(dof); const scalar_t tmp_d = displacement(dof); scalar_t h = eps_jacobian*std::abs(tmp_v); if (h < 1e-4*eps_jacobian) h = eps_jacobian; velocity(dof) = tmp_v + h; h = velocity(dof) - tmp_v; displacement(dof) = tmp_d + alphadt*h; residuals_element_component(element, component, displacement, velocity, element_residual); velocity(dof) = tmp_v; displacement(dof) = tmp_d; for (index_t enr=0; enr<2; ++enr) { const index_t noder = m_mesh->get_node(element, enr); const index_t idr = m_ideq(m_variables->dof_aqueous_concentration(noder, component)); if (idr == no_equation) continue; jacobian.push_back(dfpm::triplet_t( idr, idc, (element_residual(enr) - element_residual_orig(enr))/h )); } } } } //! \brief Update the solutions void SaturatedDiffusion::update_solution(const Vector& update, scalar_t lambda, scalar_t alpha_dt, Vector& predictor, Vector& displacement, Vector& velocity) { for (index_t node: m_mesh->range_nodes()) { for (index_t component=1; component< m_variables->nb_component(); ++component) { const index_t dof = m_variables->dof_aqueous_concentration(node, component); const index_t id = m_ideq(dof); if (id == no_equation) continue; velocity(dof) += lambda*update(id); } } //displacement = m_variables->predictor() + alpha_dt*velocity; displacement = predictor + alpha_dt*velocity; } } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/systems/saturated_react/transport_program.hpp b/src/reactmicp/systems/saturated_react/transport_program.hpp index a0dcadd..4c1c61a 100644 --- a/src/reactmicp/systems/saturated_react/transport_program.hpp +++ b/src/reactmicp/systems/saturated_react/transport_program.hpp @@ -1,140 +1,143 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_SYSTEMS_SATURATED_TRANSPORTPROGRAM_HPP #define SPECMICP_REACTMICP_SYSTEMS_SATURATED_TRANSPORTPROGRAM_HPP #include "dfpmsolver/parabolic_program.hpp" #include "variablesfwd.hpp" #include "dfpm/meshes/mesh1dfwd.hpp" #include "dfpm/types.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { class SaturatedDiffusion: public dfpmsolver::ParabolicProgram { public: SaturatedDiffusion(SaturatedVariablesPtr variables, std::vector list_fixed_nodes, std::map list_slave_nodes, std::vector list_immobile_components); SaturatedDiffusion(SaturatedVariablesPtr variables, std::vector list_fixed_nodes); //! \brief Return the number of equations index_t get_neq() const {return m_neq;} //! \brief Return the number of degrees of freedom per node index_t get_ndf() const {return m_ndf;} //! \brief Return the total number of degrees of freedom index_t get_tot_ndf() const {return m_tot_ndf;} //! \brief Method to update the variables void set_variables(SaturatedVariablesPtr variables) {m_variables = variables;} //! \brief Return the id of the equation corresponding to the degree of freedom 'id_dof' //! //! Return 'no_equation' if no equation exist index_t id_equation(index_t id_dof) const {return m_ideq(id_dof);} //! \brief Compute the residuals void compute_residuals(const Vector& displacement, const Vector& velocity, Vector& residual ); //! Compute the residuals inside 'element' for 'component' void residuals_element_component( index_t element, index_t component, const Vector& displacement, const Vector& velocity, Eigen::Vector2d& element_residual ); //! \brief Compute the jacobian void compute_jacobian(Vector& displacement, Vector& velocity, Eigen::SparseMatrix& jacobian, scalar_t alphadt ); //! \brief Compute the contribution of 'element' in the jacobian void jacobian_element( index_t element, Vector& displacement, Vector& velocity, dfpm::list_triplet_t& jacobian, scalar_t alphadt); //! \brief Update the solutions void update_solution(const Vector& update, scalar_t lambda, scalar_t alpha_dt, Vector& predictor, Vector& displacement, Vector& velocity); //! \brief Apply boundary conditions to the velocity vector //! //! by default do nothing. void apply_bc(scalar_t dt, const Vector& displacement, Vector& velocity) {} private: // number the equations void number_equations(std::vector list_fixed_nodes, std::map list_slave_nodes, std::vector list_immobile_components); index_t m_neq; index_t m_ndf; index_t m_tot_ndf; Eigen::Matrix m_ideq; mesh::Mesh1DPtr m_mesh; SaturatedVariablesPtr m_variables; bool m_is_in_residual_computation; }; } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SYSTEMS_SATURATED_TRANSPORTPROGRAM_HPP diff --git a/src/reactmicp/systems/saturated_react/transport_stagger.cpp b/src/reactmicp/systems/saturated_react/transport_stagger.cpp index 4020f30..6e7e1fc 100644 --- a/src/reactmicp/systems/saturated_react/transport_stagger.cpp +++ b/src/reactmicp/systems/saturated_react/transport_stagger.cpp @@ -1,154 +1,157 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "transport_stagger.hpp" #include "variables.hpp" #include "reactmicp/solver/staggers_base/stagger_structs.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { // class SaturatedTransportStagger:: namespace internal { //! \brief Translate a ParabolicDriverReturnCode to a StaggerReturnCode solver::StaggerReturnCode Parabolic2StaggerReturnCode(dfpmsolver::ParabolicDriverReturnCode retcode) { using ParRC = dfpmsolver::ParabolicDriverReturnCode; using StaRC = solver::StaggerReturnCode; switch (retcode) { case ParRC::ResidualMinimized: return StaRC::ResidualMinimized; break; case ParRC::ErrorMinimized: return StaRC::ErrorMinimized; break; default: // error switch(retcode) { case ParRC::MaxIterations: return StaRC::MaximumIterationsReached; break; case ParRC::StationaryPoint: return StaRC::StationaryPoint; break; case ParRC::NotConvergedYet: return StaRC::NotConvergedYet; break; default: return StaRC::UnknownError; } } } } // end namespace internal SaturatedTransportStagger::SaturatedTransportStagger(SaturatedVariablesPtr variables, std::vector list_fixed_nodes): m_program(variables, list_fixed_nodes), m_solver(m_program) { } SaturatedTransportStagger::SaturatedTransportStagger( SaturatedVariablesPtr variables, std::vector list_fixed_nodes, std::map list_slave_nodes, std::vector list_immobile_components): m_program(variables, list_fixed_nodes, list_slave_nodes, list_immobile_components), m_solver(m_program) { } //! \brief Initialize the stagger at the beginning of an iteration void SaturatedTransportStagger::initialize_timestep(scalar_t dt, VariablesBasePtr var) { m_dt = dt; SaturatedVariablesPtr true_var = cast_var_from_base(var); true_var->predictor() = true_var->displacement(); true_var->velocity().setZero(); true_var->transport_rate().setZero(); m_solver.initialize_timestep(dt, true_var->displacement()); Vector tmp = true_var->chemistry_rate(); true_var->chemistry_rate().setZero(); Eigen::VectorXd residuals; m_program.compute_residuals(true_var->displacement(), true_var->velocity(), residuals); m_residual_0 = residuals.norm(); true_var->chemistry_rate() = tmp; m_program.set_variables(true_var); } //! \brief Solve the equation for the timestep solver::StaggerReturnCode SaturatedTransportStagger::restart_timestep(VariablesBasePtr var) { SaturatedVariablesPtr true_var = cast_var_from_base(var); m_solver.velocity() = true_var->velocity(); dfpmsolver::ParabolicDriverReturnCode retcode = m_solver.restart_timestep(true_var->displacement()); // copy variables if successful if (retcode > dfpmsolver::ParabolicDriverReturnCode::NotConvergedYet) { true_var->velocity() = m_solver.velocity(); } return internal::Parabolic2StaggerReturnCode(retcode); } scalar_t SaturatedTransportStagger::get_update(VariablesBasePtr var) { return cast_var_from_base(var)->velocity().norm(); } //! \brief Compute the residuals norm scalar_t SaturatedTransportStagger::get_residual(VariablesBasePtr var) { SaturatedVariablesPtr true_var = cast_var_from_base(var); Eigen::VectorXd residuals; m_program.compute_residuals(true_var->displacement(), true_var->velocity(), residuals); return residuals.norm(); } } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/systems/saturated_react/transport_stagger.hpp b/src/reactmicp/systems/saturated_react/transport_stagger.hpp index 52171ea..0ac8bba 100644 --- a/src/reactmicp/systems/saturated_react/transport_stagger.hpp +++ b/src/reactmicp/systems/saturated_react/transport_stagger.hpp @@ -1,91 +1,94 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_SYSTEMS_SATURATED_TRANSPORTSTAGGER_HPP #define SPECMICP_REACTMICP_SYSTEMS_SATURATED_TRANSPORTSTAGGER_HPP #include "variablesfwd.hpp" #include "reactmicp/solver/staggers_base/transport_stagger_base.hpp" #include "transport_program.hpp" #include "dfpmsolver/parabolic_driver.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { using VariablesBasePtr = solver::VariablesBasePtr; class SaturatedTransportStagger: public solver::TransportStaggerBase { public: SaturatedTransportStagger(SaturatedVariablesPtr variables, std::vector list_fixed_nodes); SaturatedTransportStagger(SaturatedVariablesPtr variables, std::vector list_fixed_nodes, std::map list_slave_nodes, std::vector list_immobile_components); //! \brief Return the options of the solver dfpmsolver::ParabolicDriverOptions& options_solver() {return m_solver.get_options();} //! \brief Initialize the stagger at the beginning of an iteration void initialize_timestep(scalar_t dt, VariablesBasePtr var) override; //! \brief Solve the equation for the timestep solver::StaggerReturnCode restart_timestep(VariablesBasePtr var) override; //! \brief Compute the residuals norm scalar_t get_residual(VariablesBasePtr var) override; //! \brief Compute the residuals norm scalar_t get_residual_0(VariablesBasePtr var) override { // TODO : a slightly more optimized version would use the value from the solver return m_residual_0; } //! \brief Obtain the update scalar_t get_update(VariablesBasePtr var) override; private: scalar_t m_dt; scalar_t m_residual_0; SaturatedDiffusion m_program; dfpmsolver::ParabolicDriver m_solver; }; } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SYSTEMS_SATURATED_TRANSPORTSTAGGER_HPP diff --git a/src/reactmicp/systems/saturated_react/variables.cpp b/src/reactmicp/systems/saturated_react/variables.cpp index 4aa0385..be44449 100644 --- a/src/reactmicp/systems/saturated_react/variables.cpp +++ b/src/reactmicp/systems/saturated_react/variables.cpp @@ -1,62 +1,65 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "variables.hpp" #include "dfpm/meshes/mesh1d.hpp" namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { SaturatedVariables::SaturatedVariables(mesh::Mesh1DPtr the_mesh, RawDatabasePtr the_database): m_mesh(the_mesh), m_database(the_database) {} Vector SaturatedVariables::total_concentrations(index_t node) { Vector total_conc = porosity(node)*displacement().segment(offset_aqueous_concentration(node), nb_component()) + displacement().segment(offset_solid_concentration(node), nb_component()); return total_conc; } void SaturatedVariables::reset_main_variables() { displacement() = predictor(); velocity().setZero(); transport_rate().setZero(); chemistry_rate().setZero(); } } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp diff --git a/src/reactmicp/systems/saturated_react/variables.hpp b/src/reactmicp/systems/saturated_react/variables.hpp index 13830ab..063f2c5 100644 --- a/src/reactmicp/systems/saturated_react/variables.hpp +++ b/src/reactmicp/systems/saturated_react/variables.hpp @@ -1,253 +1,256 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_SYSTEMS_SATURATED_VARIABLES_HPP #define SPECMICP_REACTMICP_SYSTEMS_SATURATED_VARIABLES_HPP #include "database.hpp" #include "reactmicp/solver/staggers_base/variables_base.hpp" #include "specmicp/adimensional/adimensional_system_solution.hpp" #include // forward declaration // =================== #include "dfpm/meshes/mesh1dfwd.hpp" namespace specmicp { namespace reactmicp { namespace solver { using VariablesBasePtr = std::shared_ptr; } namespace systems { namespace satdiff { class SaturatedVariablesFactory; } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp // Class declaration // ================= namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { //! \brief Variables for the saturated reactive transport system //! //! Contain all the variables that need to be shared between the staggers class SaturatedVariables: public solver::VariablesBase { // SaturatedVariablesFactory should be the class to use to inialize // the variables correctly friend class SaturatedVariablesFactory; public: SaturatedVariables(mesh::Mesh1DPtr the_mesh, RawDatabasePtr the_database); //! \brief Return the mesh mesh::Mesh1DPtr get_mesh() {return m_mesh;} //! \brief Return the database RawDatabasePtr get_database() {return m_database;} //! \brief Return the number of components index_t nb_component() {return m_database->nb_component();} //! \brief Return the number of nodes index_t nb_nodes() {return m_is_fixed_composition.size();} //! \brief Return true if 'node' has a fixed composition index_t is_fixed_composition(index_t node) {return m_is_fixed_composition[node];} // Main variables // ============== //! \brief Return the main variable vector Vector& displacement() {return m_displacement;} //! \brief Return the main variable vector at the beginning of the timestep Vector& predictor() {return m_predictor;} //! \brief Return the velocity of the main variables Vector& velocity() {return m_velocity;} //! \brief Return the rate of change of the main variables due to the transport operator Vector& transport_rate() {return m_transport_rate;} //! \brief Return the rate of change of the main variables due to the chemistry operator Vector& chemistry_rate() {return m_chemistry_rate;} // Access to main variables // ======================== //! \brief Return the number of degree of freedom (per node) in the main variables vector index_t ndf() {return 2*m_database->nb_component();} //! \brief Return the offset of 'node' in the main variables vector index_t offset_node(index_t node) {return node*ndf();} //! \brief Return the offset of the aqueous concentration variables in the main variables vector index_t offset_aqueous_concentration() {return 0;} //! \brief Return the offset of the aqueous concentrations variables in the main variables vector index_t offset_aqueous_concentration(index_t node) { return offset_aqueous_concentration()+offset_node(node);} //! \brief Return the offset of the solid concentration variables in the main variables vector index_t offset_solid_concentration() {return m_database->nb_component();} //! \brief Return the offset of the solid concentrations variables in the main variables vector index_t offset_solid_concentration(index_t node) { return offset_solid_concentration()+offset_node(node);} //! \brief Return the degree of freedom number for the aqueous concentration of 'component' at 'node' index_t dof_aqueous_concentration(index_t node, index_t component) { return (component + offset_aqueous_concentration(node)); } //! \brief Return the degree of freedom number for the solid concentration of 'component' at 'node' index_t dof_solid_concentration(index_t node, index_t component) { return (component + offset_solid_concentration(node)); } //! \brief Return the aqueous concentration of 'component' at 'node' in 'var' //! //! 'var' is any of the main variables vector, it may be a velocity vector scalar_t& aqueous_concentration(index_t node, index_t component, Vector& var) { return var(dof_aqueous_concentration(node, component)); } //! \brief Return the aqueous concentration of 'component' at 'node' in main variables //! //! 'var' is any of the main variables vector, it may be a velocity vector scalar_t& aqueous_concentration(index_t node, index_t component) { return m_displacement(dof_aqueous_concentration(node, component)); } //! \brief Return the solid concentration of 'component' at 'node' in 'var' //! //! 'var' is any of the main variables vector, it may be a velocity vector scalar_t& solid_concentration(index_t node, index_t component, Vector& var){ return var(dof_solid_concentration(node, component)); } //! \brief Return the solid concentration of 'component' at 'node' in main variables //! //! 'var' is any of the main variables vector, it may be a velocity vector scalar_t& solid_concentration(index_t node, index_t component){ return m_displacement(dof_solid_concentration(node, component)); } //! \brief Return a vector containing the total concentrations computed from the main variables //! //! This is to be used to restart the chemistry computation Vector total_concentrations(index_t node); // Equilibrium // =========== //! \brief Returh the solution of the speciation solver at 'node' AdimensionalSystemSolution& equilibrium_solution(index_t node) { return m_equilibrium_solutions[node]; } // Upscaling // ========= //! \brief Return the offset for 'node' in the upscaling variables vector index_t offset_node_upscaling(index_t node) {return ndf_upscaling()*node;} //! \brief Return the number fo degree of freedom (per node) for the upscaling vector index_t ndf_upscaling() {return 5;} //! \brief Return the degree of freedom for the porosity at 'node' index_t dof_porosity(index_t node) {return 0 + offset_node_upscaling(node);} //! \brief Return the degree of freedom of the porosity velocity at 'node' index_t dof_vel_porosity(index_t node) {return 1 + offset_node_upscaling(node);} //! \brief Return the degree of freedom of the diffusion coefficient at 'node' index_t dof_diffusion_coefficient(index_t node) {return 2 + offset_node_upscaling(node);} //! \brief Return the degree of freedom of the permeability at 'node' index_t dof_permeability(index_t node) {return 3 + offset_node_upscaling(node);} //! \brief Return the fluid velocity index_t dof_fluid_velocity(index_t node) {return 4 + offset_node_upscaling(node);} //! \brief Return the porosity at 'node' scalar_t& porosity(index_t node) {return m_upscaling(dof_porosity(node));} //! \brief Return the rate of change of the porosity at 'node' scalar_t& vel_porosity(index_t node) {return m_upscaling(dof_vel_porosity(node));} //! \brief Return the diffusion coefficient at 'node' scalar_t& diffusion_coefficient(index_t node) {return m_upscaling(dof_diffusion_coefficient(node));} //! \brief Return the permeability at 'node' scalar_t& permeability(index_t node) {return m_upscaling(dof_permeability(node));} //! \brief Return the fluid velocity at 'node' scalar_t& fluid_velocity(index_t node) {return m_upscaling(dof_fluid_velocity(node));} //! \brief Return the vector of upscaling variables Vector& upscaling_variables() {return m_upscaling;} //! \brief Reset the main variables void reset_main_variables() override; private: // ############ // // Attributes // // ############ // mesh::Mesh1DPtr m_mesh; RawDatabasePtr m_database; std::vector m_is_fixed_composition; // Main variables // ============== Vector m_displacement; Vector m_predictor; Vector m_velocity; Vector m_transport_rate; Vector m_chemistry_rate; // Equilibrium // =========== std::vector m_equilibrium_solutions; // Upscaling // ========= Vector m_upscaling; }; //! \brief typedef of a shared pointer of a SaturatedVariables using SaturatedVariablesPtr = std::shared_ptr; // Casting function // ================= //! \brief Static cast to a SaturatedVariablesPtr inline SaturatedVariablesPtr cast_var_from_base(solver::VariablesBasePtr var) { return std::static_pointer_cast(var); } //! \brief Static cast from a SaturatedVariablesPtr inline solver::VariablesBasePtr cast_var_to_base(SaturatedVariablesPtr var) { return std::static_pointer_cast(var); } } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SYSTEMS_SATURATED_VARIABLES_HPP diff --git a/src/reactmicp/systems/saturated_react/variablesfwd.hpp b/src/reactmicp/systems/saturated_react/variablesfwd.hpp index cef30e9..7cf95b9 100644 --- a/src/reactmicp/systems/saturated_react/variablesfwd.hpp +++ b/src/reactmicp/systems/saturated_react/variablesfwd.hpp @@ -1,48 +1,51 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_REACTMICP_SYSTEMS_SATURATED_VARIABLESFWD_HPP #define SPECMICP_REACTMICP_SYSTEMS_SATURATED_VARIABLESFWD_HPP #include namespace specmicp { namespace reactmicp { namespace systems { namespace satdiff { class SaturatedVariables; using SaturatedVariablesPtr = std::shared_ptr; } // end namespace satdiff } // end namespace systems } // end namespace reactmicp } // end namespace specmicp #endif // SPECMICP_REACTMICP_SYSTEMS_SATURATED_VARIABLESFWD_HPP diff --git a/src/specmicp.hpp b/src/specmicp.hpp index 3f91f97..187aaee 100644 --- a/src/specmicp.hpp +++ b/src/specmicp.hpp @@ -1,45 +1,48 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ //! \file specmicp.hpp //! \brief Include this file to use SpecMiCP #include "common.hpp" #include "database/database.hpp" #include "specmicp/adimensional/adimensional_system_solver.hpp" #include "specmicp/adimensional/adimensional_system_solution.hpp" #include "specmicp/adimensional/adimensional_system_solution_extractor.hpp" #include "specmicp/adimensional/equilibrium_curve.hpp" #include "specmicp/problem_solver/formulation.hpp" #include "specmicp/problem_solver/dissolver.hpp" #include "utils/log.hpp" diff --git a/src/specmicp/adimensional/adimensional_system.cpp b/src/specmicp/adimensional/adimensional_system.cpp index 84394e3..47fe352 100644 --- a/src/specmicp/adimensional/adimensional_system.cpp +++ b/src/specmicp/adimensional/adimensional_system.cpp @@ -1,1292 +1,1295 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include #include "adimensional_system.hpp" #include "utils/log.hpp" #include "physics/constants.hpp" #include "physics/laws.hpp" #include "adimensional_system_solution.hpp" #include #include // uncomment to activate the finite difference jacobian // #define SPECMICP_DEBUG_EQUATION_FD_JACOBIAN namespace specmicp { constexpr scalar_t log10 = std::log(10.0); // Constructor // =========== // No previous solution // -------------------- AdimensionalSystem::AdimensionalSystem( RawDatabasePtr& ptrdata, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemOptions& options, const units::UnitsSet& units_set ): AdimemsionalSystemNumbering(ptrdata), OptionsHandler(options), units::UnitBaseClass(units_set), m_inert_volume_fraction(constraints.inert_volume_fraction), m_second(ptrdata), m_equations(total_dofs(), ptrdata) { specmicp_assert(ptrdata->is_valid()); m_fixed_values.setZero(ptrdata->nb_component()+1); number_eq(constraints); } // Previous solution // ----------------- AdimensionalSystem::AdimensionalSystem( RawDatabasePtr& ptrdata, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& previous_solution, const AdimensionalSystemOptions& options, const units::UnitsSet& units_set ): AdimemsionalSystemNumbering(ptrdata), OptionsHandler(options), units::UnitBaseClass(units_set), m_inert_volume_fraction(constraints.inert_volume_fraction), m_second(previous_solution), m_equations(total_dofs(), ptrdata) { specmicp_assert(ptrdata->is_valid()); m_fixed_values.setZero(ptrdata->nb_component()+1); number_eq(constraints); } // Secondary variables constructor // =============================== // No previous solution // -------------------- AdimensionalSystem::SecondaryVariables::SecondaryVariables( const RawDatabasePtr& data ): secondary_molalities(Vector::Zero(data->nb_aqueous())), loggamma(Vector::Zero(data->nb_component()+data->nb_aqueous())), gas_fugacity(Vector::Zero(data->nb_gas())), gas_concentration(Vector::Zero(data->nb_gas())), sorbed_concentrations(Vector::Zero(data->nb_sorbed())) {} // Previous solution // ----------------- AdimensionalSystem::SecondaryVariables::SecondaryVariables( const AdimensionalSystemSolution& previous_solution ): secondary_molalities(previous_solution.secondary_molalities), loggamma(previous_solution.log_gamma), gas_fugacity(previous_solution.gas_fugacities), gas_concentration(Vector::Zero(previous_solution.gas_fugacities.rows())), sorbed_concentrations(previous_solution.sorbed_molalities) {} // IdEquations constructor // ======================= AdimensionalSystem::IdEquations::IdEquations( index_t nb_dofs, const RawDatabasePtr& data ): ideq(nb_dofs, no_equation), component_equation_type(data->nb_component()+1, no_equation), fixed_activity_species(data->nb_component()+1, no_species), active_aqueous(data->nb_aqueous(), false), active_gas(data->nb_gas(), false), active_sorbed(data->nb_sorbed()) {} // Equation numbering // ================== void AdimensionalSystem::number_eq( const AdimensionalSystemConstraints& constraints ) { index_t neq = 0; // Water // ===== if (constraints.water_equation != WaterEquationType::NoEquation) { m_equations.type_equation(dof_water()) = static_cast(constraints.water_equation); if (constraints.water_equation == WaterEquationType::MassConservation) { m_fixed_values(dof_water()) = constraints.total_concentrations(dof_water()); } m_equations.add_equation(dof_water(), &neq); } // Aqueous components // ================== number_eq_aqueous_component(constraints, neq); // Surface model // ============= if (constraints.surface_model.model_type == SurfaceEquationType::Equilibrium) { // add the equation m_equations.add_equation(dof_surface(), &neq); m_equations.type_equation(dof_surface()) = static_cast(constraints.surface_model.model_type); // setup the total concentration m_fixed_values(dof_surface()) = constraints.surface_model.concentration; } // Secondary species // ================= // Secondary aqueous species // ------------------------- bool include_half_cell_reaction = (constraints.electron_constraint.equation_type != ElectronEquationType::NoEquation); bool solve_electron_equation {false}; for (auto j: m_data->range_aqueous()) { bool can_exist { true }; if ( include_half_cell_reaction or not m_data->is_half_cell_reaction(j)) for (const auto& k: m_equations.nonactive_component) { if (m_data->nu_aqueous(j, k) != 0.0) { can_exist = false; break; } } else { can_exist = false; } m_equations.set_aqueous_active(j, can_exist); if (can_exist and m_data->is_half_cell_reaction(j)) solve_electron_equation = true; //std::cout << m_data->labels_aqueous[j] << "can exist ? " << can_exist << " - logk : " << m_data->logk_aqueous(j) << std::endl; } // Gas // --- for (index_t k: m_data->range_gas()) { bool can_exist = true; for (const index_t& n: m_equations.nonactive_component) { if (m_data->nu_gas(k, n) != 0.0) { can_exist = false; break; } } m_equations.set_gas_active(k, can_exist); } // Sorbed species // -------------- for (index_t s: m_data->range_sorbed()) { // Check if the surface model is computed if (constraints.surface_model.model_type != SurfaceEquationType::Equilibrium) { m_equations.set_sorbed_active(s, false); continue; } // If so, check that all components of the sorbed species exist bool can_exist = true; for (const index_t& k: m_equations.nonactive_component) { if (m_data->nu_sorbed(s, k) != 0.0) { can_exist = false; break; } } m_equations.set_sorbed_active(s, can_exist); } // Electron equation // ----------------- if (solve_electron_equation) { m_equations.add_equation(dof_electron(), &neq); m_equations.type_equation(dof_electron()) = static_cast(constraints.electron_constraint.equation_type); if (constraints.electron_constraint.equation_type == ElectronEquationType::Equilibrium) { m_fixed_values(dof_electron()) = 0.0; } else if (constraints.electron_constraint.equation_type == ElectronEquationType::FixedpE) { m_fixed_values(dof_electron()) = constraints.electron_constraint.fixed_value; m_equations.related_species(dof_electron()) = constraints.electron_constraint.species; //assert(m_fixed_activity_species[dof_electron()] >= 0 // and m_fixed_activity_species[dof_electron()] < m_data->nb_aqueous()); //assert(m_data->is_half_cell_reaction(m_fixed_activity_species[dof_electron()])); } // scaling if (get_options().scaling_electron == 0.0) { for (index_t component : m_data->range_aqueous_component()) { if (aqueous_component_equation_type(component) == AqueousComponentEquationType::MassConservation) { get_options().scaling_electron = total_concentration_bc(component); break; } } } } // above equations are 'free' (i.e. non constrained) m_equations.nb_free_variables = neq; // following equations are complementarity conditions // Minerals // ======== m_scaling_molar_volume = m_data->scaling_molar_volume(get_units().length); for (index_t m: m_data->range_mineral()) { bool can_precipitate = true; // just check that the molar volume exist auto molar_volume = m_data->molar_volume_mineral(m); // Remove minerals that cannot precipitate for (index_t& k: m_equations.nonactive_component) { if (m_data->nu_mineral(m, k) != 0.0 and molar_volume > 0.0) { can_precipitate = false; break; // this is not a mineral that can precipitate } } if (can_precipitate) { m_equations.add_equation(dof_mineral(m), &neq); } } m_equations.nb_tot_variables = neq; m_equations.nb_complementarity_variables = m_equations.nb_tot_variables - m_equations.nb_free_variables; } void AdimensionalSystem::number_eq_aqueous_component( const AdimensionalSystemConstraints& constraints, index_t& neq ) { using EqT = AqueousComponentEquationType; // First set the charge keeper if (constraints.charge_keeper != no_species) { if (constraints.charge_keeper == 0 or constraints.charge_keeper > m_data->nb_component()) { throw std::invalid_argument("The charge keeper must be an aqueous component. Invalid argument : " + std::to_string(constraints.charge_keeper)); } m_equations.type_equation(dof_component(constraints.charge_keeper)) = static_cast(EqT::ChargeBalance); } // Then go over fix fugacity gas for (const auto& it: constraints.fixed_fugacity_cs) { if (m_equations.type_equation(dof_component(it.id_component)) != static_cast(EqT::NoEquation)) { throw std::invalid_argument("Component '" + m_data->components.get_label(it.id_component) + "' is already constrained, a fixed fugacity condition can not be applied"); } m_equations.type_equation(dof_component(it.id_component)) = static_cast(EqT::FixedFugacity); m_fixed_values(it.id_component) = it.log_value; m_equations.related_species(it.id_component) = it.id_gas; } // Then over the fix activity species for (const auto& it: constraints.fixed_activity_cs) { if (m_equations.type_equation(dof_component(it.id_component)) != static_cast(EqT::NoEquation)) { throw std::invalid_argument("Component '" + m_data->components.get_label(it.id_component) + "' is already constrained, a fixed activity condition can not be applied."); } m_equations.type_equation(dof_component(it.id_component)) = static_cast(EqT::FixedActivity); m_fixed_values(it.id_component) = it.log_value; } // Finally number the equations for (index_t component: m_data->range_aqueous_component()) { // If no equation is assigned yet if (m_equations.type_equation(dof_component(component)) == static_cast(EqT::NoEquation)) { // Mass is conserved for this component //###FIXME: H[+], HO[-] const scalar_t& total_concentration = constraints.total_concentrations(dof_component(component)); if (std::abs(total_concentration) > get_options().cutoff_total_concentration) { m_equations.type_equation(dof_component(component)) = static_cast(EqT::MassConservation); m_fixed_values(dof_component(component)) = total_concentration; m_equations.add_equation(component, &neq); } else // add component to the nonactive component list { m_equations.add_non_active_component(component); } } // If equation is already assigned else { m_equations.add_equation(component, &neq); } } if (stdlog::ReportLevel() >= logger::Debug and m_equations.nonactive_component.size() > 0) { // if in debug mode list the non active components DEBUG << "Non active components :"; for (auto it: m_equations.nonactive_component) { DEBUG << " - " << it; } } } // ================ // // // // Residuals // // // // ================ // scalar_t AdimensionalSystem::weigthed_sum_aqueous(index_t component) const { scalar_t sum = 0.0; for (index_t aqueous: m_data->range_aqueous()) { if (not is_aqueous_active(aqueous)) continue; sum += m_data->nu_aqueous(aqueous,component)*secondary_molality(aqueous); } return sum; } scalar_t AdimensionalSystem::diff_weigthed_sum_aqueous(index_t diff_component, index_t component) const { scalar_t sum = 0.0; for (index_t aqueous: m_data->range_aqueous()) { if (not is_aqueous_active(aqueous)) continue; sum += log10*m_data->nu_aqueous(aqueous,diff_component)*m_data->nu_aqueous(aqueous,component)*secondary_molality(aqueous); } return sum; } scalar_t AdimensionalSystem::weigthed_sum_sorbed(index_t component) const { scalar_t sum = 0.0; for (index_t s: m_data->range_sorbed()) { if (not is_active_sorbed(s)) continue; sum += m_data->nu_sorbed(s, component)*sorbed_species_concentration(s); } return sum; } scalar_t AdimensionalSystem::diff_weigthed_sum_sorbed(index_t diff_component, index_t component) const { scalar_t sum = 0.0; for (index_t s: m_data->range_sorbed()) { if (not is_active_sorbed(s)) continue; sum += log10*m_data->nu_sorbed(s, diff_component)*m_data->nu_sorbed(s, component)*sorbed_species_concentration(s); } return sum; } scalar_t AdimensionalSystem::diff_surface_weigthed_sum_sorbed(index_t component) const { scalar_t sum = 0.0; for (index_t s: m_data->range_sorbed()) { if (not is_active_sorbed(s)) continue; sum += log10*m_data->nb_sorption_sites(s)*m_data->nu_sorbed(s, component)*sorbed_species_concentration(s); } return sum; } scalar_t AdimensionalSystem::weigthed_sum_mineral(const Vector& x, index_t component) const { scalar_t sum = 0.0; for (index_t m: m_data->range_mineral()) { if (ideq_min(m) == no_equation or m_data->nu_mineral(m, component) == 0.0) continue; const auto concentration = saturation_mineral(x, m)/molar_volume_mineral(m); sum += m_data->nu_mineral(m, component)*concentration; } return sum; } scalar_t AdimensionalSystem::weigthed_sum_gas(index_t component) const { scalar_t sum = 0.0; for (index_t k: m_data->range_gas()) { if (not is_active_gas(k) or m_data->nu_gas(k, component) == 0.0) continue; sum += m_data->nu_gas(k, component)*gas_concentration(k); } return sum; } scalar_t AdimensionalSystem::diff_weigthed_sum_gas(index_t diff_component, index_t component) const { scalar_t sum = 0.0; for (index_t k: m_data->range_gas()) { if (not is_active_gas(k) or m_data->nu_gas(k, component) == 0.0) continue; sum += log10*m_data->nu_gas(k, diff_component)*m_data->nu_gas(k, component)*gas_concentration(k); } return sum; } scalar_t AdimensionalSystem::residual_water(const Vector& x) const { scalar_t res {0.0}; if (water_equation_type() == WaterEquationType::MassConservation) { const scalar_t conc_w = density_water()*saturation_water(x); res = total_concentration_bc(0); res -= conc_w/m_data->molar_mass_basis_si(0); res -= conc_w*weigthed_sum_aqueous(0); if (ideq_surf() != no_equation) res -= conc_w*weigthed_sum_sorbed(0); res -= weigthed_sum_mineral(x, 0); if (m_data->nb_gas() > 0) res -= weigthed_sum_gas(0); res /= total_concentration_bc(0); } else if (water_equation_type() == WaterEquationType::SaturatedSystem) { res = 1 - saturation_water(x) - m_inert_volume_fraction; for (index_t mineral: m_data->range_mineral()) { res -= saturation_mineral(x, mineral); } } return res; } scalar_t AdimensionalSystem::residual_component(const Vector &x, index_t component) const { specmicp_assert(aqueous_component_equation_type(component) == AqueousComponentEquationType::MassConservation); const scalar_t conc_w = density_water()*saturation_water(x); scalar_t res = total_concentration_bc(component); res -= conc_w*component_molality(x, component); res -= conc_w*weigthed_sum_aqueous(component); if (ideq_surf() != no_equation) res -= conc_w*weigthed_sum_sorbed(component); res -= weigthed_sum_mineral(x, component); if (m_data->nb_gas() > 0) res -= weigthed_sum_gas(component); res /= total_concentration_bc(component); return res; } scalar_t AdimensionalSystem::residual_fixed_activity(const Vector& x, index_t component) const { specmicp_assert(aqueous_component_equation_type(component) == AqueousComponentEquationType::FixedActivity); scalar_t res = (fixed_activity_bc(component) - log_gamma_component(component) - log_component_molality(x, component) ); res /= fixed_activity_bc(component); return res; } scalar_t AdimensionalSystem::residual_fixed_fugacity(const Vector& x, index_t component) const { specmicp_assert(aqueous_component_equation_type(component) == AqueousComponentEquationType::FixedFugacity); index_t id_g = m_equations.fixed_activity_species[component]; scalar_t res = fixed_fugacity_bc(component) + m_data->logk_gas(id_g); for (index_t component: m_data->range_aqueous_component()) { if (m_data->nu_gas(id_g, component) == 0) continue; res -= m_data->nu_gas(id_g, component)*( log_gamma_component(component) + log_component_molality(x, component)); } res /= fixed_fugacity_bc(component); return res; } scalar_t AdimensionalSystem::residual_mineral(const Vector& x, index_t m) const { specmicp_assert(ideq_min(m) != no_equation); scalar_t res = m_data->logk_mineral(m); for (index_t i: m_data->range_aqueous_component()) { if (m_data->nu_mineral(m, i) != 0) { const auto log_activity_i = log_component_molality(x, i) + log_gamma_component(i); res -= m_data->nu_mineral(m, i)*log_activity_i; } } if (ideq_electron() != no_equation and m_data->is_mineral_half_cell_reaction(m)) res -= m_data->nu_mineral(m, m_data->electron_index())*log_activity_electron(x); return res; } scalar_t AdimensionalSystem::residual_charge_conservation(const Vector& x) const { scalar_t res = 0.0; for (index_t i: m_data->range_aqueous_component()) { if (m_data->charge_component(i) != 0 and ideq_paq(i) != no_equation) res += m_data->charge_component(i)*component_molality(x, i); } for (index_t j: m_data->range_aqueous()) { if (m_data->charge_aqueous(j) == 0 and not is_aqueous_active(j)) continue; res += m_data->charge_aqueous(j)*secondary_molality(j); } return res; } scalar_t AdimensionalSystem::residual_surface(const Vector &x) const { specmicp_assert(ideq_surf() != no_equation); const scalar_t conc_w = density_water()*saturation_water(x); scalar_t res = surface_total_concentration() - conc_w*free_sorption_site_concentration(x); for (index_t s: m_data->range_sorbed()) { if (not is_active_sorbed(s)) continue; res -= conc_w*m_data->nb_sorption_sites(s)*sorbed_species_concentration(s); } return res/surface_total_concentration(); } scalar_t AdimensionalSystem::residual_electron(const Vector &x) const { specmicp_assert(electron_equation_type() == ElectronEquationType::Equilibrium); const scalar_t conc_w = density_water()*saturation_water(x); scalar_t res = 0.0; res -= conc_w * weigthed_sum_aqueous(m_data->electron_index()); if (ideq_surf() != no_equation) res -= conc_w * weigthed_sum_sorbed(m_data->electron_index()); res -= weigthed_sum_mineral(x, m_data->electron_index()); if (m_data->nb_gas() > 0) res -= weigthed_sum_gas(m_data->electron_index()); return res/get_options().scaling_electron; } void AdimensionalSystem::get_residuals(const Vector& x, Vector& residual) { residual.resize(total_variables()); // initialisation of 'main' secondary variables // They are especially nessary if the finite difference jacobian is used // and for the linesearch set_secondary_concentration(x); set_sorbed_concentrations(x); // // water if (ideq_w() != no_equation) residual(ideq_w()) = residual_water(x); // aqueous component for (index_t i: m_data->range_aqueous_component()) { switch (aqueous_component_equation_type(i)) { case AqueousComponentEquationType::NoEquation: break; case AqueousComponentEquationType::MassConservation: residual(ideq_paq(i)) = residual_component(x, i); break; case AqueousComponentEquationType::ChargeBalance: residual(ideq_paq(i)) = residual_charge_conservation(x); break; case AqueousComponentEquationType::FixedActivity: residual(ideq_paq(i)) = residual_fixed_activity(x, i); break; case AqueousComponentEquationType::FixedFugacity: residual(ideq_paq(i)) = residual_fixed_fugacity(x, i); break; } } // surface if (ideq_surf() != no_equation) residual(ideq_surf()) = residual_surface(x); // mineral for (index_t m: m_data->range_mineral()) { if (ideq_min(m) != no_equation) residual(ideq_min(m)) = residual_mineral(x, m); } // electron if (ideq_electron() != no_equation ) residual(ideq_electron()) = residual_electron(x); // std::cout << residual << std::endl; } // ================ // // // // Jacobian // // // // ================ // void AdimensionalSystem::get_jacobian(Vector& x, Matrix& jacobian) // //non-optimized Finite difference, for test only #ifdef SPECMICP_DEBUG_EQUATION_FD_JACOBIAN { finite_difference_jacobian(x, jacobian); return; } #else // analytical jacobian { analytical_jacobian(x, jacobian); return; } #endif void AdimensionalSystem::finite_difference_jacobian(Vector& x, Matrix& jacobian) { const int neq = total_variables(); Eigen::VectorXd res(neq); Eigen::VectorXd perturbed_res(neq); jacobian.setZero(neq, neq); get_residuals(x, res); for (int j=0; jmolar_mass_basis_si(0); tmp -= weigthed_sum_aqueous(0); tmp -= weigthed_sum_sorbed(0); tmp *= rho_w; jacobian(idw, idw) = tmp/factor; const scalar_t conc_w = density_water()*saturation_water(x); for (index_t k: m_data->range_aqueous_component()) { if (ideq_paq(k) == no_equation) continue; scalar_t tmp = 0.0; tmp -= diff_weigthed_sum_aqueous(k, 0); tmp -= diff_weigthed_sum_sorbed(k, 0); // fixme gas tmp *= conc_w; tmp -= diff_weigthed_sum_gas(k, 0); jacobian(idw, ideq_paq(k)) = tmp/factor; } if (ideq_electron() != no_equation) { scalar_t tmp = 0.0; tmp -= diff_weigthed_sum_aqueous(m_data->electron_index(), 0); tmp -= diff_weigthed_sum_sorbed(m_data->electron_index(), 0); tmp*= conc_w; tmp -= diff_weigthed_sum_gas(m_data->electron_index(), 0); jacobian(idw, ideq_electron()) = tmp/factor; } for (index_t m: m_data->range_mineral()) { if (ideq_min(m) == no_equation) continue; jacobian(idw, ideq_min(m)) = -m_data->nu_mineral(m, 0)/molar_volume_mineral(m)/factor; } } else if (water_equation_type() == WaterEquationType::SaturatedSystem) { const index_t idw = ideq_w(); jacobian(idw, idw) = -1; for (index_t m: m_data->range_mineral()) { if (ideq_min(m) == no_equation) continue; jacobian(idw, ideq_min(m)) = -1; } } } void AdimensionalSystem::jacobian_aqueous_components(Vector& x, Matrix& jacobian) { for (index_t i: m_data->range_aqueous_component()) { const index_t idp = ideq_paq(i); if (idp == no_equation) continue; switch (aqueous_component_equation_type(i)) { case AqueousComponentEquationType::NoEquation: continue; // Mass balance equation // ===================== case AqueousComponentEquationType::MassConservation: { const scalar_t conc_w = density_water()*saturation_water(x); const scalar_t factor = total_concentration_bc(i); // Aqueous components for (index_t k: m_data->range_aqueous_component()) { if (ideq_paq(k) == no_equation) continue; scalar_t tmp_iip = 0; if (k == i) tmp_iip -= component_molality(x, i)*log10; tmp_iip -= diff_weigthed_sum_aqueous(k, i); tmp_iip -= diff_weigthed_sum_sorbed(k, i); tmp_iip *= conc_w; tmp_iip -= diff_weigthed_sum_gas(k, i); jacobian(idp, ideq_paq(k)) = tmp_iip/factor; } // Minerals for (index_t m: m_data->range_mineral()) { if (ideq_min(m) == no_equation) continue; jacobian(idp, ideq_min(m)) = - m_data->nu_mineral(m, i)/molar_volume_mineral(m)/factor; } // Water if (ideq_w() != no_equation) { scalar_t tmp_iw = -component_molality(x, i); tmp_iw -= weigthed_sum_aqueous(i); tmp_iw -= weigthed_sum_sorbed(i); tmp_iw *= density_water(); jacobian(idp, ideq_w()) = tmp_iw/factor; } // Surface if (ideq_surf() != no_equation) { scalar_t tmp_s = -conc_w*diff_surface_weigthed_sum_sorbed(i); jacobian(idp, ideq_surf()) = tmp_s/factor; } // Electron if (ideq_electron() != no_equation) { scalar_t tmp = 0.0; tmp -= diff_weigthed_sum_aqueous(m_data->electron_index(), i); tmp -= diff_weigthed_sum_sorbed(m_data->electron_index(), i); tmp*= conc_w; tmp -= diff_weigthed_sum_gas(m_data->electron_index(), i); jacobian(idp, ideq_electron()) = tmp/factor; } break; } // Charge balance equation // ======================= case AqueousComponentEquationType::ChargeBalance: { // Aqueous components for (index_t k: m_data->range_aqueous_component()) { const index_t idc = ideq_paq(k); if (idc == no_equation) continue; scalar_t tmp_drdb = 0.0; if (m_data->charge_component(k) != 0.0) tmp_drdb = m_data->charge_component(k); // Secondary species for (index_t j: m_data->range_aqueous()) { if ( not is_aqueous_active(j) or m_data->nu_aqueous(j, k) == 0.0 or m_data->charge_aqueous(j) == 0.0 ) continue; scalar_t tmp_value = m_data->nu_aqueous(j, k)*m_data->charge_aqueous(j); tmp_value *= secondary_molality(j)/component_molality(x, k); tmp_drdb += tmp_value; } jacobian(idp, idc) += component_molality(x,k)*log10*tmp_drdb; } break; } // Fixed activity equation // ======================= case AqueousComponentEquationType::FixedActivity: jacobian(idp, idp) = -1.0/fixed_activity_bc(i); break; // Fixed fugacity equation // ======================= case AqueousComponentEquationType::FixedFugacity: { index_t id_g = m_equations.fixed_activity_species[i]; for (index_t k: m_data->range_aqueous_component()) { if (ideq_paq(k) == no_equation or m_data->nu_gas(id_g, k) == 0.0) continue; jacobian(idp, ideq_paq(k)) = -m_data->nu_gas(id_g, k)/fixed_fugacity_bc(i); } break; } // end case } // end switch } } void AdimensionalSystem::jacobian_minerals(Vector& x, Matrix& jacobian) { for (index_t m: m_data->range_mineral()) { const index_t idm = ideq_min(m); if (idm == no_equation) continue; for (index_t i: m_data->range_aqueous_component()) { if (ideq_paq(i) == no_equation) continue; jacobian(idm, ideq_paq(i)) = -m_data->nu_mineral(m, i); } if (ideq_electron() != no_equation and m_data->is_mineral_half_cell_reaction(m)) jacobian(idm, ideq_electron()) = -m_data->nu_mineral(m, m_data->electron_index()); } } void AdimensionalSystem::jacobian_surface(Vector& x, Matrix& jacobian) { const index_t ids = ideq_surf(); const scalar_t factor = surface_total_concentration(); const scalar_t conc_w = density_water()*saturation_water(x); specmicp_assert(ids != no_equation); scalar_t tmp_s = - free_sorption_site_concentration(x); for (index_t s: m_data->range_sorbed()) { if (not is_active_sorbed(s)) continue; tmp_s -= m_data->nb_sorption_sites(s)* m_data->nb_sorption_sites(s)*sorbed_species_concentration(s); } jacobian(ids, ids) = conc_w*log10 * tmp_s / factor; // water const index_t idw = ideq_w(); if (idw != no_equation) { const scalar_t rho_w = density_water(); scalar_t tmp_w = - free_sorption_site_concentration(x); for (index_t s: m_data->range_sorbed()) { if (not is_active_sorbed(s)) continue; tmp_w -= m_data->nb_sorption_sites(s)*sorbed_species_concentration(s); } jacobian(ids, idw) = rho_w * tmp_w / factor; } // component for (index_t k: m_data->range_aqueous_component()) { const index_t idk = ideq_paq(k); if (idk == no_equation) continue; scalar_t tmp_k = - conc_w*diff_surface_weigthed_sum_sorbed(k); jacobian(ids, idk) = tmp_k/factor; } if (ideq_electron() != no_equation) { scalar_t tmp_e = - conc_w*diff_surface_weigthed_sum_sorbed(m_data->electron_index()); jacobian(ids, ideq_electron()) = tmp_e/factor; } // water } void AdimensionalSystem::jacobian_electron(Vector& x, Matrix& jacobian) { const auto ide = ideq_electron(); const auto dofe = m_data->electron_index(); const scalar_t conc_w = density_water()*saturation_water(x); const scalar_t factor = get_options().scaling_electron; // Aqueous components for (index_t k: m_data->range_aqueous_component()) { if (ideq_paq(k) == no_equation) continue; scalar_t tmp_eip = 0; tmp_eip -= diff_weigthed_sum_aqueous(k, dofe); tmp_eip -= diff_weigthed_sum_sorbed(k, dofe); tmp_eip *= conc_w; tmp_eip -= diff_weigthed_sum_gas(k, dofe); jacobian(ide, ideq_paq(k)) = tmp_eip/factor; } // Minerals for (index_t m: m_data->range_mineral()) { if (ideq_min(m) == no_equation) continue; jacobian(ide, ideq_min(m)) = - m_data->nu_mineral(m, dofe)/molar_volume_mineral(m)/factor; } // Water if (ideq_w() != no_equation) { scalar_t tmp_iw = 0; tmp_iw -= weigthed_sum_aqueous(dofe); tmp_iw -= weigthed_sum_sorbed(dofe); tmp_iw *= density_water(); jacobian(ide, ideq_w()) = tmp_iw/factor; } // Surface if (ideq_surf() != no_equation) { scalar_t tmp_s = -conc_w*diff_surface_weigthed_sum_sorbed(dofe); jacobian(ide, ideq_surf()) = tmp_s/factor; } // Electron if (ideq_electron() != no_equation) { scalar_t tmp = 0.0; tmp -= diff_weigthed_sum_aqueous(dofe, dofe); tmp -= diff_weigthed_sum_sorbed(dofe, dofe); tmp*= conc_w; tmp -= diff_weigthed_sum_gas(dofe, dofe); jacobian(ide, ide) = tmp/factor; } } // ========================== // // // // Secondary variables // // // // ========================== // void AdimensionalSystem::set_secondary_variables(const Vector& x) { set_saturation_gas_phase(x); set_pressure_fugacity(x); if (ideq_surf() != no_equation) set_sorbed_concentrations(x); set_secondary_concentration(x); compute_log_gamma(x); } void AdimensionalSystem::set_saturation_gas_phase(const Vector& x) { m_second.saturation_gas = 1 - saturation_water(x) - sum_saturation_minerals(x) - m_inert_volume_fraction; } void AdimensionalSystem::set_pressure_fugacity(const Vector& x) { const auto rt = constants::gas_constant*temperature(); for (index_t k: m_data->range_gas()) { if (not is_active_gas(k)) continue; scalar_t logp = -m_data->logk_gas(k); for (index_t i: m_data->range_aqueous_component()) { if (m_data->nu_gas(k, i) == 0.0) continue; const auto log_activity_i = log_component_molality(x, i) + log_gamma_component(i); logp += m_data->nu_gas(k, i) * log_activity_i; } if (ideq_electron() != no_equation and m_data->is_gas_half_cell_reaction(k)) logp += m_data->nu_gas(k, m_data->electron_index())*log_activity_electron(x); m_second.gas_fugacity(k) = pow10(logp); const auto pressure = gas_fugacity(k)*gas_total_pressure(); const auto concentration = saturation_gas_phase()*pressure/rt; m_second.gas_concentration(k) = concentration; } } void AdimensionalSystem::set_secondary_concentration(const Vector& x) { for (index_t j: m_data->range_aqueous()) { if (not is_aqueous_active(j)) { m_second.secondary_molalities(j) = 0.0; continue; } scalar_t logconc = -m_data->logk_aqueous(j) - log_gamma_secondary(j); for (index_t k: m_data->range_aqueous_component()) { if (m_data->nu_aqueous(j, k) == 0) continue; const auto log_activity_k = log_component_molality(x, k) + log_gamma_component(k); logconc += m_data->nu_aqueous(j, k)*log_activity_k; } if (ideq_electron() != no_equation and m_data->is_half_cell_reaction(j)) logconc += m_data->nu_aqueous(j, m_data->electron_index())*log_activity_electron(x); m_second.secondary_molalities(j) = pow10(logconc); } } void AdimensionalSystem::set_sorbed_concentrations(const Vector& x) { for (index_t s: m_data->range_sorbed()) { if (not is_active_sorbed(s)) { m_second.sorbed_concentrations(s) = 0.0; continue; } scalar_t logconc = -m_data->logk_sorbed(s) + m_data->nb_sorption_sites(s)*(log_free_sorption_site_concentration(x)); for (index_t k: m_data->range_aqueous_component()) { if (m_data->nu_sorbed(s, k) == 0.0) continue; const auto activity_k = log_component_molality(x, k) + log_gamma_component(k); logconc += m_data->nu_sorbed(s, k)*activity_k; } if (ideq_electron() != no_equation and m_data->is_sorbed_half_cell_reaction(s)) logconc += m_data->nu_sorbed(s, m_data->electron_index())*log_activity_electron(x); m_second.sorbed_concentrations(s) = pow10(logconc); } } void AdimensionalSystem::set_ionic_strength(const Vector& x) { scalar_t ionic = 0; for (index_t i: m_data->range_aqueous_component()) { if (ideq_paq(i) == no_equation or m_data->charge_component(i) == 0) continue; ionic += component_molality(x, i)*std::pow(m_data->charge_component(i),2); } for (index_t j: m_data->range_aqueous()) { if (not is_aqueous_active(j) or m_data->charge_aqueous(j) == 0) continue; ionic += secondary_molality(j)*std::pow(m_data->charge_aqueous(j),2); } ionic_strength() = ionic/2; } void AdimensionalSystem::compute_log_gamma(const Vector& x) { set_ionic_strength(x); const scalar_t sqrti = std::sqrt(ionic_strength()); for (index_t i: m_data->range_aqueous_component()) { if (ideq_paq(i) == no_equation) { log_gamma_component(i) = 0.0; continue; } log_gamma_component(i) = laws::extended_debye_huckel( ionic_strength(), sqrti, m_data->charge_component(i), m_data->a_debye_component(i), m_data->b_debye_component(i) ); } for (index_t j: m_data->range_aqueous()) { if (not is_aqueous_active(j)) { log_gamma_secondary(j) = 0.0; continue; } log_gamma_secondary(j) = laws::extended_debye_huckel( ionic_strength(), sqrti, m_data->charge_aqueous(j), m_data->a_debye_aqueous(j), m_data->b_debye_aqueous(j) ); } } bool AdimensionalSystem::hook_start_iteration(const Vector& x, scalar_t norm_residual) { if (not get_options().non_ideality) { set_secondary_variables(x); // we still need to compute secondary species ! // if (norm_residual < nb_free_variables()*get_options().start_non_ideality_computation) // { // set_secondary_variables(x); // } return true; } not_in_linesearch = true; scalar_t previous_norm = m_second.loggamma.norm(); bool may_have_converged = false; if (norm_residual < nb_free_variables()*get_options().start_non_ideality_computation) { // Use fixed point iterations for non-ideality for (int i=0; i 1e-6) { WARNING << "Activity coefficient have not converged !" << std::endl << "output can not be trusted\n Difference : " +std::to_string(std::abs(previous_norm - m_second.loggamma.norm())); } } // Set the correct value for the water total saturation if (ideq_w() == no_equation) { xtot(dof_water()) = saturation_water(x); } return AdimensionalSystemSolution(xtot, m_second.secondary_molalities, m_second.loggamma, m_second.ionic_strength, m_second.gas_fugacity, m_second.sorbed_concentrations, m_inert_volume_fraction); } // Water, saturation and density // ============================== scalar_t AdimensionalSystem::density_water() const { return laws::density_water(units::celsius(25.0), length_unit(), mass_unit()); } scalar_t AdimensionalSystem::saturation_water(const Vector& x) const { if (ideq_w() != no_equation) return x(ideq_w()); else return 1.0 - sum_saturation_minerals(x) - m_inert_volume_fraction; } scalar_t AdimensionalSystem::saturation_mineral(const Vector& x, index_t mineral) const { specmicp_assert(mineral >= 0 and mineral < m_data->nb_mineral()); if (ideq_min(mineral) == no_equation) return 0.0; else return x(ideq_min(mineral)); } scalar_t AdimensionalSystem::sum_saturation_minerals(const Vector& x) const { scalar_t sum_saturations = 0.0; for (index_t mineral: m_data->range_mineral()) { sum_saturations += saturation_mineral(x, mineral); } return sum_saturations; } // Starting guess // ============== void AdimensionalSystem::reasonable_starting_guess(Vector &xtot) { xtot.resize(total_dofs()); xtot(dof_water()) = 0.8; for (index_t i: m_data->range_aqueous_component()) { xtot(dof_component(i)) = -4.0; } if (ideq_surf() != no_equation) xtot(dof_surface()) = std::log10(0.8*surface_total_concentration()); else xtot(dof_surface()) = -HUGE_VAL; if (ideq_electron() != no_equation) xtot(dof_electron()) = -4; else xtot(dof_electron()) = -HUGE_VAL; xtot.segment(offset_minerals(), m_data->nb_mineral()).setZero(); m_second = SecondaryVariables(m_data); } void AdimensionalSystem::reasonable_restarting_guess(Vector& xtot) { std::random_device rd; std::mt19937 gen(rd()); std::uniform_real_distribution<> dis(-2, 2); xtot(dof_water()) = 0.5; for (index_t i: m_data->range_aqueous_component()) { //if (xtot(dof_component(i)) > 0 or xtot(dof_component(i)) < -9) xtot(i) = get_options().restart_concentration + dis(gen); } if (ideq_surf() != no_equation) xtot(dof_surface()) = std::log10(0.8*surface_total_concentration()); else xtot(dof_surface()) = -HUGE_VAL; if (ideq_electron() != no_equation) xtot(dof_electron()) = -4; else xtot(dof_electron()) = -HUGE_VAL; xtot.segment(offset_minerals(), m_data->nb_mineral()).setZero(); m_second = SecondaryVariables(m_data); } } // end namespace specmicp diff --git a/src/specmicp/adimensional/adimensional_system.hpp b/src/specmicp/adimensional/adimensional_system.hpp index 5eb97a0..1e87685 100644 --- a/src/specmicp/adimensional/adimensional_system.hpp +++ b/src/specmicp/adimensional/adimensional_system.hpp @@ -1,698 +1,702 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ + #ifndef SPECMICP_ADIMENSIONALSYSTEM_HPP #define SPECMICP_ADIMENSIONALSYSTEM_HPP //! \file adimensional_system.hpp The MiCP program to solve speciation #include "common.hpp" #ifndef SPECMICP_DATABASE_HPP #include "database.hpp" #endif #include "micpsolver/micpprog.hpp" #include "physics/units.hpp" #include "utils/options_handler.hpp" #include "adimensional_system_numbering.hpp" #include "adimensional_system_structs.hpp" //! \namespace specmicp main namespace for the SpecMiCP solver namespace specmicp { class AdimensionalSystemSolution; //! \brief The equilibrium speciation problem //! //! Represent the equilibrium speciation problem as a Mixed Complementarity program //! //! The main variables are : //! - \f$S^t_w\f$ the volume fraction of water (total saturation) //! - \f$b_i\f$ the molality of aqueous component //! - \f$S^t_m\f$ the volume fraction of mineral //! //! The solid phase equilibrium is solved by using a complementarity formulation //! \f[ S^t_m \geq 0, \; - \mathrm{SI}_m \geq 0 , \; \mathrm{and} \; - S^t_m \mathrm{SI}_m = 0 \f] //! //! The secondary variables (molalities of secondary aqueous species, gas fugacities, ionic strength, ...) //! are solved using a fixed point iteration at the beginning of each iteration. //! class AdimensionalSystem : public micpsolver::MiCPProg, public AdimemsionalSystemNumbering, public OptionsHandler, private units::UnitBaseClass { public: //! \brief Create a reduced system //! //! \param ptrdata Shared pointer to the thermodynamic database //! \param constraints Constraints to apply to the system //! \param options Numerical options, mainly related to the secondary variables //! \param units_set The set of units AdimensionalSystem(RawDatabasePtr& ptrdata, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemOptions& options=AdimensionalSystemOptions(), const units::UnitsSet& units_set=units::UnitsSet() ); //! \brief Create a reduced system, initialize the system using a previous solution //! //! \param ptrdata Shared pointer to the thermodynamic database //! \param constraints Constraints to apply to the system //! \param previous_solution The previous solution to use for initialization //! \param options Numerical options, mainly related to the secondary variables //! \param units_set The set of units AdimensionalSystem( RawDatabasePtr& ptrdata, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& previous_solution, const AdimensionalSystemOptions& options=AdimensionalSystemOptions(), const units::UnitsSet& units_set=units::UnitsSet() ); // Variables // ========== //! \brief Return the total number of variables index_t total_variables() const {return m_equations.nb_tot_variables;} //! \brief Return the number of 'free' variables (not subject to complementarity conditions) index_t nb_free_variables() const {return m_equations.nb_free_variables;} //! \brief Return the number of variables subjected to the complementarity conditions index_t nb_complementarity_variables() const {return m_equations.nb_complementarity_variables;} //! \brief Return a pointer to the database RawDatabasePtr get_database() {return m_data;} // The linear system // ================== //! \brief Return the residual for the water conservation equation //! //! \param x Vector of the main variables scalar_t residual_water(const Vector& x) const; //! \brief Return the residual for the conservation equation of component (i) //! //! For water (i==0) use the method : 'residual_water' //! \param x Vector of the main variables //! \param i Index of the component (in the database) scalar_t residual_component(const Vector& x, index_t i) const; //! \brief Compute the residual for the surface sorption //! \param x Vector of the main variables scalar_t residual_surface(const Vector& x) const; //! \brief Equilibrium condition for the minerals //! \param x Vector of the main variables //! \param i Index of the component (in the database) scalar_t residual_mineral(const Vector& x, index_t m) const; //! \brief Return the residual of the charge conservation equation //! //! This equation may be used instead of a mass conservation equation to //! explicitely enforce the electroneutrality. //! The component corresponding to this equation is called the charge keeper //! \param x Vector of the main variables scalar_t residual_charge_conservation(const Vector& x) const; //! \brief Return the residual corresponding to a fixed fugacity equation //! \param x Vector of the main variables //! \param component Index of the corresponding component (in the database) scalar_t residual_fixed_fugacity(const Vector& x, index_t component) const; //! \brief Return the residual corresponding to a fixed activity equation //! //! If 'component ' is charged, then a charge keeper should be set. //! \param x Vector of the main variables //! \param component Index of the corresponding component (in the database) scalar_t residual_fixed_activity(const Vector& x, index_t component) const; //! \brief Return the residual corresponding to the electron equation scalar_t residual_electron(const Vector &x) const; //! \brief Return the residuals //! //! \param x Vector of the main variables //! \param[out] residual Vector containing the residuals void get_residuals(const Vector& x, Vector& residual); //! \brief Return the jacobian //! //! \param x Vector of the main variables //! \param[out] jacobian Dense matrix representing the jacobian void get_jacobian(Vector& x, Matrix& jacobian); // Getters // ####### // Equation id access // ================== //! \brief Return the equation id //! \param i Index of the main variable (in the set of the main variables) index_t ideq(index_t i) const {return m_equations.ideq[i];} //! \brief Return the equation number for conservation of water index_t ideq_w() const {return m_equations.ideq[dof_water()];} //! \brief Return the equation number of component 'i' //! \param i Index of the component (in the database) index_t ideq_paq(index_t i) const { specmicp_assert(i < m_data->nb_component()); return m_equations.ideq[dof_component(i)]; } //! \brief Return the equation number of the electron equation index_t ideq_electron() const { return m_equations.ideq[dof_electron()]; } //! \brief Return the equation number of the free surface concentration index_t ideq_surf() const { return m_equations.ideq[dof_surface()]; } //! \brief Return the equation number of mineral 'm' //! \param m Index of the mineral (in the database) index_t ideq_min(index_t m) const { specmicp_assert(m < m_data->nb_mineral()); return m_equations.ideq[dof_mineral(m)]; } // Equation type // ------------- //! \brief Return the type of equation used for the solvent //! //! Can be no equation, mass conservation, saturation of the system, ... //! //! \sa #WaterEquationType, #aqueous_component_equation_type, #AqueousComponentEquationType WaterEquationType water_equation_type() const { return static_cast(m_equations.type_equation(dof_water())); } //! \brief Return the type of equation for aqueous species 'component' //! //! For water used the method #water_equation_type //! \param component Index of the aqueous component (in the database) //! //! \sa #AqueousComponentEquationType, water_equation_type, #WaterEquationType AqueousComponentEquationType aqueous_component_equation_type(index_t component) const { specmicp_assert(component > 0 and component < m_data->nb_component()); return static_cast(m_equations.type_equation(dof_component(component))); } //! \brief Return the type of equation for the electron ElectronEquationType electron_equation_type() const { return static_cast(m_equations.type_equation(dof_electron())); } //! \brief Return true if an equation exist for this component //! //! \param component Index of the component (in the database) bool is_active_component(index_t component) const { specmicp_assert(component < m_data->nb_component() and component > no_species); return m_equations.id_equation(dof_component(component)) != no_equation; } //! \brief Return the surface model SurfaceEquationType surface_model() const { if (ideq_surf() == no_equation) return SurfaceEquationType::NoEquation; return SurfaceEquationType::Equilibrium; } // Variables // ========= // Primary // ------- //! \brief Return the saturation of water //! //! \param x Vector of the main variables scalar_t saturation_water(const Vector& x) const; //! \brief Return the density of water scalar_t density_water() const; //! \brief Return the volume fraction of a mineral //! //! \param x Vector of the main variables //! \param mineral Index of the mineral (in the database) scalar_t saturation_mineral(const Vector& x, index_t mineral) const; //! \brief Return the volume of minerals //! //! \param mineral Index of the mineral (in the database) scalar_t molar_volume_mineral(index_t mineral) const { return m_scaling_molar_volume*m_data->unsafe_molar_volume_mineral(mineral); } //! \brief Return the sum of saturation of the minerals //! //! This corresponds to the volume fraction of the solid phases (minus the inert phase) //! \param x Vector of the main variables scalar_t sum_saturation_minerals(const Vector& x) const; //! \brief Return the log_10 of the component molality //! //! \param x Vector of the main variables //! \param component Index of the aqueous component (in the database) scalar_t log_component_molality(const Vector& x, index_t component) const { specmicp_assert(ideq_paq(component) != no_equation and component < m_data->nb_component()); return x(ideq_paq(component)); } //! \brief Return the molality of 'component' //! //! \param x Vector of the main variables //! \param component Index of the aqueous component (in the database) scalar_t component_molality(const Vector& x, index_t component) const { return pow10(log_component_molality(x, component)); } //! \brief Return the concentration of free sorption site scalar_t free_sorption_site_concentration(const Vector& x) const { return pow10(log_free_sorption_site_concentration(x)); } //! \brief Return the log_10 of the free sorption site concentration scalar_t log_free_sorption_site_concentration(const Vector& x) const { specmicp_assert(ideq_surf() != no_equation); return x(ideq_surf()); } //! \brief log activity of the electron scalar_t log_activity_electron(const Vector& x) const { specmicp_assert(ideq_electron() != no_equation); return x(ideq_electron()); } //! \brief return the activity of the electro scalar_t activity_electron(const Vector& x) const { return pow10(log_activity_electron(x)); } // Secondary // --------- //! \brief Return the concentration of secondary species 'aqueous' //! //! \param aqueous Index of the secondary aqueous species (in the database) scalar_t secondary_molality(index_t aqueous) const { if (not is_aqueous_active(aqueous)) return 0.0; return m_second.secondary_molalities(dof_aqueous(aqueous)); } //! \brief Return true if 'aqueous' is active //! //! i.e. Return true if all its component are present in the system //! \param aqueous Index of the secondary aqueous species (in the database) bool is_aqueous_active(index_t aqueous) const { return m_equations.active_aqueous[dof_aqueous(aqueous)]; } //! \brief Return log_10(γ_i) where i is a component //! //! γ is the activity coefficient //! \param component Index of the aqueous component (in the database) scalar_t log_gamma_component(index_t component) const { return m_second.loggamma(dof_component_gamma(component)); } //! \brief Return log_10(γ_j) where j is a secondary aqueous species //! //! γ is the activity coefficient //! \param aqueous Index of the secondary aqueous species (in the database) scalar_t log_gamma_secondary(index_t aqueous) const { return m_second.loggamma(dof_aqueous_gamma(aqueous)); } //! \brief Return the ionic strength scalar_t ionic_strength() const noexcept { return m_second.ionic_strength; } //! \brief Return the total concentration of 'component' //! //! Only use this method if the mass is conserved for 'component' //! \param component Index of the aqueous component (in the database) scalar_t total_concentration_bc(index_t component) const { specmicp_assert((component > 0 and aqueous_component_equation_type(component) == AqueousComponentEquationType::MassConservation) or ( water_equation_type() == WaterEquationType::MassConservation)); return m_fixed_values(component); } //! \brief Return the fixed activity of 'component' //! //! Only use this method if 'component' has a fixed activity constraint //! \param component Index of the aqueous component (in the database) scalar_t fixed_activity_bc(index_t component) const { specmicp_assert(aqueous_component_equation_type(component) == AqueousComponentEquationType::FixedActivity); return m_fixed_values(component); } //! \brief Return the fixed fugacity value for 'component' scalar_t fixed_fugacity_bc(index_t component) const { specmicp_assert(aqueous_component_equation_type(component) == AqueousComponentEquationType::FixedFugacity); return m_fixed_values(component); } //! \brief Return the total concentration for the electron scalar_t electron_total_concentration() const { return 0.0; } // Gas // --- //! \brief Return the fugacity of 'gas' //! //! \param gas Index of the gas (in the database) scalar_t gas_fugacity(index_t gas) const { return m_second.gas_fugacity(gas); } //! \brief Return the concentration of 'gas' in the system //! //! \param gas Index of the gas (in the database) scalar_t gas_concentration(index_t gas) const { return m_second.gas_concentration(gas); } //! \brief Return true if gas is active //! //! \param gas Index of the gas (in the database) bool is_active_gas(index_t gas) const { return m_equations.active_gas[gas]; } //! \brief Return the volume fraction (total saturation) of the gas phase scalar_t saturation_gas_phase() const noexcept { return m_second.saturation_gas; } // Sorbed species // -------------- //! \brief Return the surface total concentration const scalar_t& surface_total_concentration() const { return m_fixed_values(dof_surface()); } //! \brief Return true if 'sorbed' is an active species //! \param sorbed Index of the sorbed species (in the database) bool is_active_sorbed(index_t sorbed) const { return m_equations.active_sorbed[sorbed]; } //! \brief Return the molality of the sorbed species 'sorbed' //! \param sorbed Index of the sorbed species (in the database) const scalar_t& sorbed_species_concentration(index_t sorbed) const { return m_second.sorbed_concentrations(sorbed); } // Pressure and temperature // ------------------------ //! \brief Return the gas pressure //! //! This is a fixed value (1 atm) scalar_t gas_total_pressure() const { return units::convert_pressure(1.01325e5, length_unit()); } //! \brief Return the temperature //! //! This is a fixed value (25°C) scalar_t temperature() const noexcept { return 273.16+25; } // Solution // ================= //! \brief Return the equilibrium state of the system, the Solution of the speciation problem //! //! \param xtot the complete set of main variables //! \param x the reduced set of main variables, only the variables with an equation AdimensionalSystemSolution get_solution(Vector& xtot, const Vector& x); // Algorithm // ######### //! \brief Compute the ionic strength //! //! \param x Vector of the main variables void set_ionic_strength(const Vector& x); //! \brief Compute the activity coefficients //! //! \param x Vector of the main variables void compute_log_gamma(const Vector& x); //! \brief Compute the secondary aqueous species molalities //! //! \param x Vector of the main variables void set_secondary_concentration(const Vector& x); //! \brief Compute the secondary variables //! //! \param x Vector of the main variables void set_secondary_variables(const Vector& x); //! \brief Compute the gas phase volume fraction //! //! \param x Vector of the main variables void set_saturation_gas_phase(const Vector& x); //! \brief Compute the fugacity for all the gas //! //! \param x Vector of the main variables void set_pressure_fugacity(const Vector& x); //! \brief Compute the sorbed species concentrations //! //! \param x Vector of the main variables void set_sorbed_concentrations(const Vector& x); //! \brief This function is called at the beginning of each iteration by the solver //! //! It does the fixed-point iteration to compute the secondary variables //! \param x Vector of the main variables //! \param norm_residual Norm of the current residuals bool hook_start_iteration(const Vector &x, scalar_t norm_residual); //! \brief Return a scale factor to avoid negative mass during Newton's iteration //! //! \param x Vector of the main variables //! \param update Update of the current iteration double max_lambda(const Vector &x, const Vector &update); //! \brief Return the component that does not exist in the solution (inactive dof) const std::vector& get_non_active_component() {return m_equations.nonactive_component;} //! \brief A reasonable (well... maybe...) starting guess //! //! \param xtot Vector of the main variables //! \sa #reasonable_starting_guess void reasonable_starting_guess(Vector& xtot); //! \brief A reasonable (maybe...) restarting guess //! //! \param xtot Vector of the main variables //! \sa #reasonable_restarting_guess void reasonable_restarting_guess(Vector& xtot); //! \brief Return true if 'component' is the charge keeper //! //! The charge keeper is the component added or removed to satisfy the charge balance //! \param component Index of the aqueous component (in the database) bool is_charge_keeper(index_t component) { return (aqueous_component_equation_type(component) == AqueousComponentEquationType::ChargeBalance); } //! \brief Compute the jacobian analytically void analytical_jacobian(Vector& x, Matrix& jacobian); //! \brief Compute the jacobian using finite difference void finite_difference_jacobian(Vector& x, Matrix& jacobian); //! \brief Set the units void set_units(const units::UnitsSet& unit_set) { units::UnitBaseClass::set_units(unit_set); m_scaling_molar_volume = m_data->scaling_molar_volume(unit_set.length); } // Private Members and attributes // ############################## private: //! \brief Sum of the aqueous molalities weighted by the stoichiometric coefficient of 'component' scalar_t weigthed_sum_aqueous(index_t component) const; //! \brief Sum of the sorbed concentration weighted by the stoichiometric coefficient of 'component' scalar_t weigthed_sum_sorbed(index_t component) const; //! \brief Sum of the mineral concentration weighted by the stoichiometric coefficient of 'component' scalar_t weigthed_sum_mineral(const Vector& x, index_t component) const; //! \brief Sum of the gas concentration weigthed by the stoichiometric coefficient of 'component' scalar_t weigthed_sum_gas(index_t component) const; //! \brief Derivative of the aqueous weigthed sum with respect to 'diff_component' //! \sa weigthed_sum_aqueous scalar_t diff_weigthed_sum_aqueous(index_t diff_component, index_t component) const; //! \brief Derivative of the sorbed weigthed sum with respect to 'diff_component' //! \sa weigthed_sum_sorbed scalar_t diff_weigthed_sum_sorbed(index_t diff_component, index_t component) const; //! \brief Derivative of the sorbed weigthed sum with respect to the free surface concentration //! \sa weigthed_sum_sorbed scalar_t diff_surface_weigthed_sum_sorbed(index_t component) const; //! \brief Derivative of the gas weigthed sum with respect to 'diff_component' //! \sa weigthed_sum_sorbed scalar_t diff_weigthed_sum_gas(index_t diff_component, index_t component) const; // Jacobian // ######## //! \brief Compute the water equation contribution to the Jacobian //! \param x Reduced vector of the main variables //! \param jacobian Dense matrix containing the jacobian void jacobian_water(Vector& x, Matrix& jacobian); //! \brief Compute the aqueous components equation contribution to the Jacobian //! \param x Reduced vector of the main variables //! \param jacobian Dense matrix containing the jacobian void jacobian_aqueous_components(Vector& x, Matrix& jacobian); //! \brief Compute the mineral equations contribution to the Jacobian //! \param x Reduced vector of the main variables //! \param jacobian Dense matrix containing the jacobian void jacobian_minerals(Vector& x, Matrix& jacobian); //! \brief Compute the contribution of the surface sorption equation to te Jacobian //! \param x Reduced vector of the main variables //! \param jacobian Dense matrix containing the jacobian void jacobian_surface(Vector& x, Matrix& jacobian); //! \brief Compute the contribution of the electron equation to te Jacobian //! \param x Reduced vector of the main variables //! \param jacobian Dense matrix containing the jacobian void jacobian_electron(Vector& x, Matrix& jacobian); // Equation numbering // ################## //! \brief Number the equations //! \param constraints the constraints to apply to the system //! \sa number_eq_aqueous_component void number_eq(const AdimensionalSystemConstraints& constraints); //! \brief Number the equations for the aqueous components //! \param constraints the constraints to apply to the system //! \param[in,out] neq the number of equations in the system //! \sa number_eq void number_eq_aqueous_component( const AdimensionalSystemConstraints& constraints, index_t& neq ); // Setter // ###### // main variables // -------------- // they are set by the solver // Secondary variables // ------------------- //! \brief Return a reference to log_10(γ_i) where i is a component scalar_t& log_gamma_component(index_t component) { return m_second.loggamma(dof_component_gamma(component)); } //! \brief Return a reference to log_10(γ_j) where j is a secondary aqueous species scalar_t& log_gamma_secondary(index_t aqueous) { return m_second.loggamma(dof_aqueous_gamma(aqueous)); } //! \brief Return a reference to the ionic strength scalar_t& ionic_strength() { return m_second.ionic_strength; } // Attributes // ########## //! \struct AdimensionalSystem::SecondaryVariables //! \brief Contains information about the secondary variables struct SecondaryVariables { scalar_t ionic_strength {0.0}; //!< The ionic Strength scalar_t saturation_gas {0.0}; //!< The gas saturation Vector secondary_molalities; //!< The secondary molalities Vector loggamma; //!< The log of activity coefficients Vector gas_fugacity; //!< The gas fugacities Vector gas_concentration; //!< The gas concentrations Vector sorbed_concentrations; //!< The sorbed concentrations //! \brief Initialization without a previous solution SecondaryVariables(const RawDatabasePtr& data); //! \brief Initialization with a previous solution SecondaryVariables(const AdimensionalSystemSolution& previous_solution); }; //! \struct IdEquations //! \brief BookKeeper for the equations id and type struct IdEquations { index_t nb_tot_variables; index_t nb_free_variables; index_t nb_complementarity_variables; std::vector ideq; std::vector component_equation_type; std::vector fixed_activity_species; std::vector nonactive_component; std::vector active_aqueous; std::vector active_gas; std::vector active_sorbed; //! \brief Initialize the data structure IdEquations(index_t nb_dofs, const RawDatabasePtr& data); //! \brief Return the equation id const index_t& id_equation(index_t dof) const { return ideq[dof]; } //! \brief Return a reference to the equation id index_t& id_equation(index_t dof) { return ideq[dof]; } //! \brief Return a reference to the type of equation of 'dof' index_t& type_equation(index_t dof) { return component_equation_type[dof]; } //! \brief Return the equation type for 'dof' index_t type_equation(index_t dof) const { return component_equation_type[dof]; } //! \brief Return the related species for dof //! //! The exact meaning of this relation is dependant upon the equation type index_t& related_species(index_t dof) { return fixed_activity_species[dof]; } //! \brief Add a non active component to the system void add_non_active_component(index_t id) { nonactive_component.push_back(id); } //! \brief Add an equation void add_equation(index_t id, index_t *neq) { ideq[id] = *neq; ++(*neq); } //! \brief Set the active flag of aqueous species 'id' to 'is_active' void set_aqueous_active(index_t id, bool is_active) { active_aqueous[id] = is_active; } //! \brief Set the active flag of gas 'id' to 'is_active' void set_gas_active(index_t id, bool is_active) { active_gas[id] = is_active; } //! \brief Set the active flag of sorbed species 'id' to 'is_active' void set_sorbed_active(index_t id, bool is_active) { active_sorbed[id] = is_active; } }; bool not_in_linesearch; scalar_t m_inert_volume_fraction; scalar_t m_scaling_molar_volume; Vector m_fixed_values; SecondaryVariables m_second; IdEquations m_equations; }; } // end namespace specmicp #endif // SPECMICP_ADIMENSIONALSYSTEM_HPP diff --git a/src/specmicp/adimensional/adimensional_system_numbering.hpp b/src/specmicp/adimensional/adimensional_system_numbering.hpp index f2b5cdd..7b9e43e 100644 --- a/src/specmicp/adimensional/adimensional_system_numbering.hpp +++ b/src/specmicp/adimensional/adimensional_system_numbering.hpp @@ -1,117 +1,120 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_ADIMENSIONALSYSTEMNUMBERING #define SPECMICP_ADIMENSIONALSYSTEMNUMBERING #include "common.hpp" #ifndef SPECMICP_DATABASE_HPP #include "database.hpp" #endif namespace specmicp { //! \brief The equation numbering scheme for the adimensional system //! //! This is the numbering of the main variables (the non-reduced vector) class AdimemsionalSystemNumbering { public: //! \brief Initialize the numbering scheme //! \param ptr_database shared_ptr to the database container AdimemsionalSystemNumbering(RawDatabasePtr ptr_database): m_data(ptr_database) {} //! \brief Return the dof for water conservation index_t dof_water() const noexcept {return m_data->water_index();} //! \brief Return the dof corresponding to the component conservation //! \param component Index of the component index_t dof_component(index_t component) const NOEXCEPT { specmicp_assert(component < m_data->nb_component() and component >= 0); return component; } //! \brief Return the dof corresponding to the electron activity index_t dof_electron() const noexcept { return m_data->electron_index(); } //! \brief Return the dof corresponding to the sorption sites conservation index_t dof_surface() const noexcept { return m_data->nb_component(); } //! \brief Return the offset for the dof of minerals //! \sa dof_mineral index_t offset_minerals() const noexcept { return m_data->nb_component()+1; } //! \brief Return the dof for mineral 'mineral' //! \param mineral Index of the mineral (in the database) index_t dof_mineral(index_t mineral) const NOEXCEPT { specmicp_assert(mineral < m_data->nb_mineral() and mineral >= 0); return offset_minerals()+mineral; } //! \brief Return the number of dofs index_t total_dofs() const noexcept { return m_data->nb_component()+m_data->nb_mineral()+1; } // secondary species //! \brief dof of the activitiy coefficient for 'component' //! \param component Index of the component (in the database) index_t dof_component_gamma(index_t component) const { specmicp_assert(component < m_data->nb_component() and component > 0); return component; } //! \brief dof of a secondary aqueous species //! \param aqueous Index of the aqueous species (in the database) index_t dof_aqueous(index_t aqueous) const { specmicp_assert(aqueous < m_data->nb_aqueous()); return aqueous; } //! \brief dof of the activity coefficient for 'aqueous' //! \param aqueous Index of the aqueous species (in the database) index_t dof_aqueous_gamma(index_t aqueous) const { specmicp_assert(aqueous < m_data->nb_aqueous() and aqueous >= 0); return m_data->nb_component()+aqueous; } //! \brief Return the database RawDatabasePtr get_database() { return m_data; } protected: RawDatabasePtr m_data; }; } // end namespace specmicp #endif // SPECMICP_ADIMENSIONALSYSTEMNUMBERING diff --git a/src/specmicp/adimensional/adimensional_system_pcfm.cpp b/src/specmicp/adimensional/adimensional_system_pcfm.cpp index 4444946..a95fa94 100644 --- a/src/specmicp/adimensional/adimensional_system_pcfm.cpp +++ b/src/specmicp/adimensional/adimensional_system_pcfm.cpp @@ -1,196 +1,199 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "adimensional_system_pcfm.hpp" #include "adimensional_system.hpp" #include #include "utils/log.hpp" namespace specmicp { // AdimensionalSystemPCFM AdimensionalSystemPCFM::AdimensionalSystemPCFM(std::shared_ptr program): m_data(program->get_database()), m_program(program) { check_validity(); } AdimensionalSystemPCFM::AdimensionalSystemPCFM( std::shared_ptr program, const PCFMOptions& options): OptionsHandler(options), m_data(program->get_database()), m_program(program) { check_validity(); } bool AdimensionalSystemPCFM::check_validity() { bool is_valid = true; if (m_program->water_equation_type() != WaterEquationType::NoEquation) { ERROR << "The implementation of the positive continuous fraction method does not compute the conservation of water"; is_valid = false; } if (m_program->get_database()->nb_mineral() != 0.0) { WARNING << "The implementation of the positive continuous fraction method does not compute the solid phase assemblage"; is_valid = false; } return is_valid; } PCFMReturnCode AdimensionalSystemPCFM::solve(Vector &x) { index_t cnt = 0; m_errors.setZero(m_program->total_variables()); while (cnt < get_options().max_iterations) { one_iteration(x); scalar_t error = m_errors.lpNorm(); DEBUG << "PCFM error : " << error << " ?< " << get_options().tolerance; if (not std::isfinite(error)) return PCFMReturnCode::Error; if (error < get_options().tolerance) return PCFMReturnCode::Success; ++cnt; } if (cnt == get_options().max_iterations) return PCFMReturnCode::MaxIterationsReached; return PCFMReturnCode::NotConvergedYet; } void AdimensionalSystemPCFM::one_iteration(Vector &x) { m_program->set_secondary_concentration(x); m_program->set_sorbed_concentrations(x); for (index_t component: m_data->range_aqueous_component()) { if (m_program->ideq_paq(component) != no_equation) { solve_component(component, x); } } if (m_program->ideq_surf() != no_equation) { solve_surface(x); } } void AdimensionalSystemPCFM::solve_component(index_t component, Vector& x) { specmicp_assert(component > 0 and component < m_data->nb_component() and "Must be an aqueous component"); specmicp_assert(m_program->ideq_paq(component) != no_equation and "No corresponding equation for this component"); specmicp_assert(m_program->aqueous_component_equation_type(component) == AqueousComponentEquationType::MassConservation); const scalar_t total_concentration = m_program->total_concentration_bc(component); scalar_t conc_w = m_program->density_water()*m_program->saturation_water(x); scalar_t sum_reac = conc_w*m_program->component_molality(x, component); scalar_t sum_prod = 0.0; // compute the lhs and rhs of the mass balance so that every contribution is positive if (total_concentration >= 0) { sum_prod += total_concentration; } else { sum_reac -= total_concentration; } for (index_t aqueous: m_data->range_aqueous()) { if (m_data->nu_aqueous(aqueous, component) > 0) sum_reac += conc_w*m_data->nu_aqueous(aqueous, component)*m_program->secondary_molality(aqueous); else sum_prod -= conc_w*m_data->nu_aqueous(aqueous, component)*m_program->secondary_molality(aqueous); } for (index_t sorbed: m_data->range_sorbed()) { if (m_data->nu_sorbed(sorbed, component) > 0) sum_reac += m_data->nu_sorbed(sorbed, component)*m_program->sorbed_species_concentration(sorbed); else sum_prod -= m_data->nu_sorbed(sorbed, component)*m_program->sorbed_species_concentration(sorbed); } specmicp_assert(std::isfinite(sum_reac)); specmicp_assert(sum_reac > 0.0 && "Sum of reactants concentration should be positive"); specmicp_assert(sum_prod > 0.0 && "Sum of products should be positive"); // compute the step size scalar_t theta; const scalar_t factor = (sum_prod/sum_reac); if (sum_reac > sum_prod) theta = 0.9 - 0.8*factor; else theta = 0.9 - 0.8/factor; // theta *= get_options().theta_factor; scalar_t new_conc = (1-theta + theta*factor)*m_program->component_molality(x, component); x(m_program->ideq_paq(component)) = std::log10(new_conc); m_errors(m_program->ideq_paq(component)) = std::abs(sum_reac - sum_prod)/(sum_reac + sum_prod); } void AdimensionalSystemPCFM::solve_surface(Vector& x) { specmicp_assert(m_program->ideq_surf() != no_equation); specmicp_assert(m_program->surface_total_concentration() > 0); scalar_t sum_prod = m_program->surface_total_concentration(); scalar_t sum_reac = m_program->free_sorption_site_concentration(x); for (index_t sorbed: m_data->range_sorbed()) { sum_reac += m_data->nb_sorption_sites(sorbed)*m_program->sorbed_species_concentration(sorbed); } specmicp_assert(std::isfinite(sum_reac)); specmicp_assert(sum_reac > 0.0 && "Sum of reactants concentration should be positive"); specmicp_assert(sum_prod > 0.0 && "Sum of products should be positive"); scalar_t theta; const scalar_t factor = (sum_prod/sum_reac); if (sum_reac > sum_prod) theta = 0.9 - 0.8*factor; else theta = 0.9 - 0.8/factor; // theta *= get_options().theta_factor; scalar_t new_conc = (1-theta + theta*factor)*m_program->free_sorption_site_concentration(x); x(m_program->ideq_surf()) = std::log10(new_conc); m_errors(m_program->ideq_surf()) = std::abs(sum_reac - sum_prod)/(sum_reac + sum_prod); } } // end namespace specmicp diff --git a/src/specmicp/adimensional/adimensional_system_pcfm.hpp b/src/specmicp/adimensional/adimensional_system_pcfm.hpp index 2d3bb4b..e639fff 100644 --- a/src/specmicp/adimensional/adimensional_system_pcfm.hpp +++ b/src/specmicp/adimensional/adimensional_system_pcfm.hpp @@ -1,98 +1,101 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_ADIMENSIONALSYSTEM_PCFM_HPP #define SPECMICP_ADIMENSIONALSYSTEM_PCFM_HPP #include "database.hpp" #include "adimensional_system_pcfm_structs.hpp" #include "utils/options_handler.hpp" //! \file adimensional_system_pcfm.hpp The positive continuous fraction method namespace specmicp { // forward declaration class AdimensionalSystem; //! \brief The positive continuous fraction method //! //! It is particularly well adapted for aqueous only systems //! //! References : //! - Carrayrou (2002) class AdimensionalSystemPCFM: public OptionsHandler { public: AdimensionalSystemPCFM(std::shared_ptr program); AdimensionalSystemPCFM( std::shared_ptr program, const PCFMOptions& options); //! \brief Pre-solve the problem //! \param x Vector of the main variable (should be initialized) PCFMReturnCode solve(Vector& x); //! \brief Run one iteration of the PCFM method void one_iteration(Vector& x); //! \brief Run the PCFM method for one component void solve_component(index_t component, Vector& x); //! \brief Run the PCFM method for the surface equation void solve_surface(Vector& x); //! \brief Check the validity of the problem; for now just print error message //! \return Return true if the problem is true bool check_validity(); private: RawDatabasePtr m_data; std::shared_ptr m_program; Vector m_errors; }; //! \brief Initialize a system using the positive continuous fraction method //! //! \param program shared_ptr to the program //! \param x Vector of the main variables (should be initialized) //! //! \sa AdimensionalSystemPCFM inline PCFMReturnCode positive_continuous_fraction_method( std::shared_ptr program, Vector& x ) { return AdimensionalSystemPCFM(program).solve(x); } } // end namespace specmicp #endif // SPECMICP_ADIMENSIONALSYSTEM_PCFM_HPP diff --git a/src/specmicp/adimensional/adimensional_system_pcfm_structs.hpp b/src/specmicp/adimensional/adimensional_system_pcfm_structs.hpp index 084e983..53be75f 100644 --- a/src/specmicp/adimensional/adimensional_system_pcfm_structs.hpp +++ b/src/specmicp/adimensional/adimensional_system_pcfm_structs.hpp @@ -1,68 +1,71 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_ADIMENSIONALSYSTEMPCFMSTRUCTS_HPP #define SPECMICP_ADIMENSIONALSYSTEMPCFMSTRUCTS_HPP #include "common.hpp" //! \file adimensional_system_pcfm_structs.hpp Enum and structs used by the pcfm solver //! \sa specmicp::AdimensionalSystemPCFM namespace specmicp { //! \enum PCFMReturnCode The return codes for the positive continuous fraction method //! \sa specmicp::AdimensionalSystemPCFM enum class PCFMReturnCode { LolThatsNotSupposedToHappen, //! Bummer... Error, //!< Some kind of error happended MaxIterationsReached, //!< The maximum number of iterations was reached NotConvergedYet, //!< The problem has not converged yet Success //!< Success ! }; //! \struct PCFMOptions Options for the Positive continuous fraction method //! \sa specmicp::AdimensionalSystemPCFM struct PCFMOptions { index_t max_iterations; //!< The maximum number of iterations scalar_t tolerance; //!< The tolerance (should be relatively high around 0.5) scalar_t theta_factor; //!> multiplicatif factor for theta PCFMOptions(): max_iterations(100), tolerance(0.5), theta_factor(0.25) {} }; } // end namespace specmicp #endif diff --git a/src/specmicp/adimensional/adimensional_system_solution.hpp b/src/specmicp/adimensional/adimensional_system_solution.hpp index 98bfcc0..00ea768 100644 --- a/src/specmicp/adimensional/adimensional_system_solution.hpp +++ b/src/specmicp/adimensional/adimensional_system_solution.hpp @@ -1,81 +1,84 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLUTION_HPP #define SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLUTION_HPP #include "common.hpp" //! \file adimensional_system_solution.hpp Structure to contain the solution returned by AdimensionalSystemSolution namespace specmicp { //! \brief Solution of an adimensional system struct AdimensionalSystemSolution { Vector main_variables; //!< The main variables Vector secondary_molalities; //!< Molalities of secondary aqueous Vector log_gamma; //!< Log_10 of activities coefficients scalar_t ionic_strength; //!< Ionic strength Vector gas_fugacities; //!< Gas fugacities Vector sorbed_molalities; //!< Sorbed molalities scalar_t inert_volume_fraction; //!< Inert volume fraction bool is_valid; //!< True if this is a valid solution //! \brief Build an empty solution AdimensionalSystemSolution(): is_valid(false) {} //! \brief Build a valid solution AdimensionalSystemSolution( const Vector& variables, const Vector& aqueous_molalities, const Vector& loggama, scalar_t the_ionic_strength, const Vector& fugacities, const Vector& sorbed_species_molalities, scalar_t the_inert_volume_fraction=0.0 ): main_variables(variables), secondary_molalities(aqueous_molalities), log_gamma(loggama), ionic_strength(the_ionic_strength), gas_fugacities(fugacities), sorbed_molalities(sorbed_species_molalities), inert_volume_fraction(the_inert_volume_fraction), is_valid(true) {} }; } // end namespace specmicp #endif // SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLUTION_HPP diff --git a/src/specmicp/adimensional/adimensional_system_solution_extractor.cpp b/src/specmicp/adimensional/adimensional_system_solution_extractor.cpp index 2283bf4..7367cdc 100644 --- a/src/specmicp/adimensional/adimensional_system_solution_extractor.cpp +++ b/src/specmicp/adimensional/adimensional_system_solution_extractor.cpp @@ -1,223 +1,226 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "adimensional_system_solution_extractor.hpp" #include "physics/laws.hpp" #include "database/database.hpp" namespace specmicp { scalar_t AdimensionalSystemSolutionExtractor::density_water() const { return laws::density_water(units::celsius(25.0), length_unit(), mass_unit()); } scalar_t AdimensionalSystemSolutionExtractor::mass_concentration_water() const { return density_water()*total_saturation_water(); } scalar_t AdimensionalSystemSolutionExtractor::pH() const { // find species responsible for pH index_t id = m_data->get_id_component("HO[-]"); if (id != no_species) { return 14+log_activity_component(id); } else { id = m_data->get_id_component("H[+]"); if (id != no_species) return -log_activity_component(id); throw std::runtime_error("No component corresponding to the dissociation of water !"); } } scalar_t AdimensionalSystemSolutionExtractor::total_saturation_minerals() const { return m_solution.main_variables.segment(offset_minerals(), m_data->nb_mineral()).sum(); } scalar_t AdimensionalSystemSolutionExtractor::mole_concentration_mineral(index_t mineral) const { return total_saturation_mineral(mineral)/m_data->molar_volume_mineral(mineral, length_unit()); } scalar_t AdimensionalSystemSolutionExtractor::mass_concentration_mineral(index_t mineral) const { return mole_concentration_mineral(mineral)*m_data->molar_mass_mineral(mineral, mass_unit()); } //! \brief Return the total aqueous concentration scalar_t AdimensionalSystemSolutionExtractor::total_aqueous_concentration(index_t component) const { scalar_t conc = molality_component(component); for (index_t aqueous: m_data->range_aqueous()) { if (m_data->nu_aqueous(aqueous, component) != 0.0) { conc += m_data->nu_aqueous(aqueous, component)*molality_aqueous(aqueous); } } return conc; } //! \brief Return the total solid concentration scalar_t AdimensionalSystemSolutionExtractor::total_solid_concentration(index_t component) const { scalar_t conc= 0; for (index_t mineral: m_data->range_mineral()) { if (m_data->nu_mineral(mineral, component) != 0.0) { conc += m_data->nu_mineral(mineral, component) * total_saturation_mineral(mineral) / m_data->molar_volume_mineral(mineral, length_unit()); } } return conc; } //! \brief Return the total immobile concentration scalar_t AdimensionalSystemSolutionExtractor::total_immobile_concentration(index_t component) const { scalar_t conc= total_solid_concentration(component); const scalar_t conc_w = density_water()*volume_fraction_water(); for (index_t sorbed: m_data->range_sorbed()) { if (m_data->nu_sorbed(sorbed, component) != 0.0) { conc += conc_w*m_data->nu_sorbed(sorbed, component) * molality_sorbed_species(sorbed); } } return conc; } //! Return the saturation index for 'mineral' scalar_t AdimensionalSystemSolutionExtractor::saturation_index(index_t mineral) const { scalar_t saturation_index = - m_data->logk_mineral(mineral); for (index_t component: m_data->range_aqueous_component()) { saturation_index += m_data->nu_mineral(mineral, component) * log_activity_component(component); } return saturation_index; } //! Return the saturation index for 'mineral_kinetic' scalar_t AdimensionalSystemSolutionExtractor::saturation_index_kinetic(index_t mineral_kinetic) const { scalar_t saturation_index = - m_data->logk_mineral_kinetic(mineral_kinetic); for (index_t component: m_data->range_aqueous_component()) { saturation_index += m_data->nu_mineral_kinetic(mineral_kinetic, component) * log_activity_component(component); } return saturation_index; } // ########################### // // // // Modificator // // // // ########################### // void AdimensionalSystemSolutionModificator::scale_total_concentration( index_t component, scalar_t new_value) { const scalar_t old_value = total_solid_concentration(component); const scalar_t factor = new_value/old_value; m_nonconst_solution.main_variables.segment(dof_mineral(0), m_data->nb_mineral()) *= factor; } void AdimensionalSystemSolutionModificator::remove_solids() { m_nonconst_solution.main_variables.segment(dof_mineral(0), m_data->nb_mineral()).setZero(); } Vector AdimensionalSystemSolutionModificator::set_minerals_kinetics(std::vector& list_species) { index_t nb_kinetics = list_species.size(); index_t nb_new_mineral = m_data->nb_mineral() - nb_kinetics; std::vector minerals_to_keep; minerals_to_keep.reserve(nb_new_mineral); std::vector new_kinetics_index(nb_kinetics, no_species); Vector saturation_kinetics(nb_kinetics); index_t new_ind_eq = m_data->nb_component(); index_t new_ind_kin = 0; index_t tot_ind_kin = m_data->nb_mineral_kinetic(); // ###TODO optimize for (index_t mineral: m_data->range_mineral()) { auto is_kin = std::find(list_species.begin(), list_species.end(), mineral); // If mineral is still at equilibrium if (is_kin == list_species.end()) { minerals_to_keep.push_back(mineral); m_nonconst_solution.main_variables(new_ind_eq) = total_saturation_mineral(mineral); ++new_ind_eq; } // If mineral is governed by kinetics else { saturation_kinetics(new_ind_kin) = total_saturation_mineral(mineral); ++new_ind_kin; // save the new index (index in the kinetics vector) // The order is conserved ! new_kinetics_index[is_kin - list_species.begin()] = tot_ind_kin; ++tot_ind_kin; } } specmicp_assert(new_ind_eq == m_data->nb_component()+nb_new_mineral); // change the database database::Database dbhandler(m_data); dbhandler.minerals_keep_only(minerals_to_keep); // update the list of species list_species.swap(new_kinetics_index); // resize m_nonconst_solution.main_variables.conservativeResize(m_data->nb_component()+nb_new_mineral); return saturation_kinetics; } } // end namespace specmicp diff --git a/src/specmicp/adimensional/adimensional_system_solution_extractor.hpp b/src/specmicp/adimensional/adimensional_system_solution_extractor.hpp index 3c5eed7..7244275 100644 --- a/src/specmicp/adimensional/adimensional_system_solution_extractor.hpp +++ b/src/specmicp/adimensional/adimensional_system_solution_extractor.hpp @@ -1,336 +1,339 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLUTIONEXTRACTOR_HPP #define SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLUTIONEXTRACTOR_HPP #include "common.hpp" #include "database.hpp" #include "adimensional_system_solution.hpp" #include "physics/units.hpp" #include "physics/constants.hpp" #include "adimensional_system_numbering.hpp" //! \file adimensional_system_solution_extractor.hpp Obtain data from AdimensionalSystemSolution namespace specmicp { //! \class AdimensionalSystemSolutionextractor //! \brief Obtain physical variables from AdimensionalSystemSolution //! //! This class can't modify the solution, use #AdimensionalSystemSolutionModificator for this. //! //! \sa AdimensionalSystemSolutionModificator class AdimensionalSystemSolutionExtractor: public AdimemsionalSystemNumbering, public units::UnitBaseClass { public: // public members // ############### //! \brief Constructor //! //! \param solution Reference to a solution from the AdimensionalSystemSolution //! \param thedatabase shared_ptr to the database //! \param units_set Units used by the solver AdimensionalSystemSolutionExtractor( const AdimensionalSystemSolution& solution, RawDatabasePtr thedatabase, units::UnitsSet units_set): AdimemsionalSystemNumbering(thedatabase), units::UnitBaseClass(units_set), m_solution(solution) {} // Primary variables // ================= // water // ------ //! \brief Return the total saturation of water //! Deprecated, use the correct name : volume fraction scalar_t total_saturation_water() const { return m_solution.main_variables(dof_water());} //! \brief Return the volume fraction of water scalar_t volume_fraction_water() const { return m_solution.main_variables(dof_water());} //! \brief Return the density of water scalar_t density_water() const; // electron // --------- //! \brief Return the log of the activity electron scalar_t log_activity_electron() const { return m_solution.main_variables(dof_electron()); } //! \brief Return the activity of the electron scalar_t activity_electron() const { return pow10(log_activity_electron()); } //! \brief Return the pE scalar_t pE() const { return -log_activity_electron(); } scalar_t Eh() const { return std::log(10.0)*constants::gas_constant*units::celsius(25.0)/constants::faraday_constant*pE(); } // component // --------- //! \brief Return the log_10 of the molality of 'component' scalar_t log_molality_component(index_t component) const { if (component == m_data->water_index()) return std::log10(1.0/m_data->molar_mass_basis(component, mass_unit())); else if (component == m_data->electron_index()) return -HUGE_VAL; return m_solution.main_variables(dof_component(component));} //! \brief Return the molality of 'component' scalar_t molality_component(index_t component) const { if (component == m_data->water_index()) return 1.0/m_data->molar_mass_basis(component, mass_unit()); else if (component == m_data->electron_index()) return 0.0; return pow10(log_molality_component(component)); } // solid phases // ------------ //! \brief Return the total saturation of 'mineral' //! deprecated, use the volume fraction instead scalar_t total_saturation_mineral(index_t mineral) const { return m_solution.main_variables(dof_mineral(mineral)); } //! \brief Return the volume fraction of 'mineral' scalar_t volume_fraction_mineral(index_t mineral) const { return m_solution.main_variables(dof_mineral(mineral)); } // surface // ------- //! \brief Return the concentration of free surface scalar_t log_free_surface_concentration() const { return m_solution.main_variables(dof_surface()); } //! \brief Return the concentration of free surface scalar_t free_surface_concentration() const { return pow10(m_solution.main_variables(dof_surface())); } // Secondary variables // =================== //! \brief Return the ionic strength of the solution scalar_t ionic_strength() const {return m_solution.ionic_strength;} // component // --------- //! \brief Return the log_10 of the activity coefficient of 'component' scalar_t log_activity_coefficient_component(index_t component) const { return m_solution.log_gamma(dof_component_gamma(component)); } //! \brief Return the activity coefficient of 'component' scalar_t activity_coefficient_component(index_t component) const { return pow10(log_activity_coefficient_component(component)); } //! \brief Return the log_10 of the activity of 'component scalar_t log_activity_component(index_t component) const { return log_molality_component(component) + log_activity_coefficient_component(component); } //! \brief Return the activity of 'component' scalar_t activity_component(index_t component) const { return pow10(log_activity_component(component)); } // aqueous species // --------------- //! \brief Return the molality of secondary specis 'aqueous' scalar_t molality_aqueous(index_t aqueous) const { return m_solution.secondary_molalities(dof_aqueous(aqueous));} //! \brief Return the log10 of the activity ocefficient of secondary species 'aqueous' scalar_t log_activity_coefficient_aqueous(index_t aqueous) const { return m_solution.log_gamma(dof_aqueous_gamma(aqueous)); } //! \brief Return the activity coefficient of secondary species 'aqueous' scalar_t activity_coefficient_aqueous(index_t aqueous) const { return pow10(log_activity_coefficient_aqueous(aqueous)); } //! \brief Return the activity of secondary species 'aqueous' scalar_t activity_aqueous(index_t aqueous) const { return activity_coefficient_aqueous(aqueous)*molality_aqueous(aqueous); } // gas fugacity // ------------- //! \brief Return fugacity for 'gas' scalar_t fugacity_gas(index_t gas) const { return m_solution.gas_fugacities(gas); } // Sorbed species // -------------- //! \brief Return sorbed species molalities for 'sorbed' scalar_t molality_sorbed_species(index_t sorbed) const { return m_solution.sorbed_molalities(sorbed); } // Tertiary variables // ================== // Water // ----- //! \brief Return the saturation of water scalar_t saturation_water() const {return volume_fraction_water()/porosity();} //! \brief Return the mass concentration of water scalar_t mass_concentration_water() const; //! \brief Return the pH of the solution scalar_t pH() const; // Component // --------- //! \brief Return the total aqueous concentration scalar_t total_aqueous_concentration(index_t component) const; //! \brief Return the total solid concentration scalar_t total_solid_concentration(index_t component) const; //! \brief Return the total immobile concentration scalar_t total_immobile_concentration(index_t component) const; // Gas phase // --------- //! \brief Return the saturation of the gas phase scalar_t saturation_gas_phase() const {return 1-saturation_water();} //! \brief Return the total saturation of the gas phase //! Depreacated, use volume fraction instead scalar_t total_saturation_gas_phase() const {return porosity() - saturation_water();} //! \brief Return the volume fraction occupied by the gas phase scalar_t volume_fraction_gas_phase() const {return porosity() - saturation_water();} // Component // --------- // Solid phases // ------------ //! \brief Return the concentration of 'mineral' //! //! \param mineral Index of the mineral (in the database) scalar_t mole_concentration_mineral(index_t mineral) const; //! \brief Return the mass concentration of 'mineral' //! //! \param mineral Index of the mineral (in the database) scalar_t mass_concentration_mineral(index_t mineral) const; //! \brief Return the total saturation of all minerals //! Deprecated, use the volume fraction function instead scalar_t total_saturation_minerals() const; //! \brief Return the volume fraction occupied by the minerals scalar_t volume_fraction_minerals() const {return total_saturation_minerals();} //! \brief Return the inert volume fraction scalar_t volume_fraction_inert() const {return m_solution.inert_volume_fraction;} //! \brief Return the porosity scalar_t porosity() const {return 1 - total_saturation_minerals() - volume_fraction_inert();} //! \brief Return the saturation index for 'mineral' //! //! \param mineral Index of the mineral (in the database) scalar_t saturation_index(index_t mineral) const; //! \brief Return the saturation index for 'mineral_kinetic' //! //! \param mineral_kinetic Index of the mineral governed by the kinetic (in the database) scalar_t saturation_index_kinetic(index_t mineral_kinetic) const; //! \brief Return the vector of main variables, can be used to initialize the solver Vector get_main_variables() const {return m_solution.main_variables;} protected: // private attributes // ################## const AdimensionalSystemSolution& m_solution; }; //! \class AdimensionalSystemSolutionModificator //! \brief Special class to modify (scale) the solution //! //! The set of modification are limited to straightforward modification that does not modify the equilibrium class AdimensionalSystemSolutionModificator: public AdimensionalSystemSolutionExtractor { public: AdimensionalSystemSolutionModificator( AdimensionalSystemSolution& solution, RawDatabasePtr thedatabase, units::UnitsSet units_set): AdimensionalSystemSolutionExtractor(solution, thedatabase, units_set), m_nonconst_solution(solution) {} //! \brief Scale the solid phases with respect to the total solid concentration of a component //! //! \param component Index of the component (in the database) //! \param new_value New value of the total solid concentration void scale_total_concentration(index_t component, scalar_t new_value); //! \brief Remove the solid phases void remove_solids(); //! \brief Set some species to be considered as governed by kinetics //! //! \param[in,out] list_species list of minerals to flag as kinetics, //! The list will contain the new indexes of the corresponding solid phases; //! \return the vector of saturation //! //! This function modify the databse Vector set_minerals_kinetics(std::vector& list_species); private: AdimensionalSystemSolution& m_nonconst_solution; }; } // end namespace specmicp #endif // SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLUTIONEXTRACTOR_HPP diff --git a/src/specmicp/adimensional/adimensional_system_solver.cpp b/src/specmicp/adimensional/adimensional_system_solver.cpp index 7485300..88bc7a4 100644 --- a/src/specmicp/adimensional/adimensional_system_solver.cpp +++ b/src/specmicp/adimensional/adimensional_system_solver.cpp @@ -1,425 +1,428 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "micpsolver/micpsolver.hpp" #include "adimensional_system_solver.hpp" #include "specmicp/adimensional/adimensional_system_solution.hpp" #include "adimensional_system_pcfm.hpp" #include "utils/log.hpp" #include namespace specmicp { AdimensionalSystemSolution solve_equilibrium( std::shared_ptr data, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolverOptions& options ) { AdimensionalSystemSolver solver(data, constraints, options); Vector variables; micpsolver::MiCPPerformance perf = solver.solve(variables, true); if (perf.return_code <= micpsolver::MiCPSolverReturnCode::NotConvergedYet) throw std::runtime_error("Failed to solve the problem"); return solver.get_raw_solution(variables); } // constructor // ----------- AdimensionalSystemSolver::AdimensionalSystemSolver( RawDatabasePtr data, const AdimensionalSystemConstraints& constraints, AdimensionalSystemSolverOptions options ): OptionsHandler(options), m_data(data), m_system(std::make_shared( data, constraints, options.system_options, options.units_set )), m_var(Vector::Zero(data->nb_component()+1+data->nb_mineral())) {} AdimensionalSystemSolver::AdimensionalSystemSolver( RawDatabasePtr data, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& previous_solution, AdimensionalSystemSolverOptions options ): OptionsHandler(options), m_data(data), m_system(std::make_shared( data, constraints, previous_solution, options.system_options, options.units_set )), m_var(Vector::Zero(data->nb_component()+1+data->nb_mineral())) {} AdimensionalSystemSolution AdimensionalSystemSolver::get_raw_solution(Vector& x) { set_true_variable_vector(x); return m_system->get_solution(x, m_var); } // Solving the system // ------------------ micpsolver::MiCPPerformance AdimensionalSystemSolver::solve(Vector& x, bool init) { m_system->set_units(get_options().units_set); if (init) { m_system->reasonable_starting_guess(x); if (get_options().use_pcfm) { run_pcfm(x); } } else if (get_options().force_pcfm) { run_pcfm(x); } set_true_variable_vector(x); micpsolver::MiCPPerformance perf = solve_system(); int cnt = 0; while (perf.return_code < micpsolver::MiCPSolverReturnCode::Success // != micpsolver::MiCPSolverReturnCode::ResidualMinimized and get_options().allow_restart and cnt < 3) { WARNING << "Failed to solve the system ! Return code :" << (int) perf.return_code << ". We shake it up and start again"; const scalar_t save_penalization_factor = get_options().solver_options.penalization_factor; const bool save_scaling = get_options().solver_options.use_scaling; get_options().solver_options.use_scaling = true; if (save_penalization_factor == 1) get_options().solver_options.penalization_factor = 0.8; set_return_vector(x); m_system->reasonable_restarting_guess(x); if (get_options().use_pcfm or get_options().force_pcfm) run_pcfm(x); set_true_variable_vector(x); micpsolver::MiCPPerformance perf2 = solve_system(); get_options().solver_options.penalization_factor = save_penalization_factor; get_options().solver_options.use_scaling = save_scaling; perf += perf2; ++cnt; } if (perf.return_code > micpsolver::MiCPSolverReturnCode::NotConvergedYet) set_return_vector(x); return perf; } micpsolver::MiCPPerformance AdimensionalSystemSolver::solve_system() { micpsolver::MiCPSolver solver(m_system); solver.set_options(get_options().solver_options); solver.solve(m_var); return solver.get_perfs(); } // Variables management // --------------------- void AdimensionalSystemSolver::set_true_variable_vector(const Vector& x) { const std::vector& non_active_component = m_system->get_non_active_component(); // if ((non_active_component.size() == 0) // and // (m_system->ideq_surf() != no_equation)) // { // // we still copy the data, if we failed to solve the problem, we can restart // if (m_system->is_active_component(0)) // m_var = x; // direct copy // else // m_var = x.block(2, 0, x.rows()-2, 1); // for (int i=0; iget_options().new_component_concentration; // } // } // } // else // remove the dof that are not part of the problem // FIXME { uindex_t new_i = 0; if (m_system->is_active_component(0)) { m_var(0) = x(m_system->dof_water()); ++new_i; } for (index_t i: m_data->range_aqueous_component()) { const auto it = std::find(non_active_component.cbegin(), non_active_component.cend(),i); if (it != non_active_component.cend()) continue; scalar_t value = x(m_system->dof_component(i)); if (value == -HUGE_VAL) // check for previously undefined value { value = m_system->get_options().new_component_concentration; } m_var(new_i) = value; ++new_i; } if (m_system->ideq_surf() != no_equation) { m_var(new_i) = x(m_system->dof_surface()); ++new_i; } if (m_system->ideq_electron() != no_equation) { m_var(new_i) = x(m_system->dof_electron()); ++new_i; } for (index_t m: m_data->range_mineral()) { bool to_keep = true; for (auto it=non_active_component.begin(); it!=non_active_component.end(); ++it) { if (m_data->nu_mineral(m, *it) != 0) to_keep = false; } if (to_keep) { m_var(new_i) = x(m_system->dof_mineral(m)); ++new_i; } } m_var.conservativeResize(new_i); specmicp_assert(new_i == (unsigned) m_system->total_variables()); } } void AdimensionalSystemSolver::set_return_vector(Vector& x) { const std::vector& non_active_component = m_system->get_non_active_component(); // FIXME // if (non_active_component.size() == 0 and m_system->ideq_surf() != no_equation) // shortcut // { // if (m_system->is_active_component(0)) // x = m_var; //direct copy // else // x.block(1, 0, x.rows()-1, 1) = m_var; // // at that point we should have the correct solution // } // else { uindex_t new_i = 0; if (m_system->is_active_component(0)) { x(m_system->dof_water()) = m_var(new_i); ++new_i; } else { x(m_system->dof_water()) = m_system->saturation_water(x); } for (index_t i: m_data->range_aqueous_component()) { const auto it = std::find(non_active_component.cbegin(), non_active_component.cend(),i); if (it != non_active_component.cend()) { x(m_system->dof_component(i)) = -HUGE_VAL; continue; } x(m_system->dof_component(i)) = m_var(new_i) ; ++new_i; } if (m_system->ideq_surf() != no_equation) { x(m_system->dof_surface()) = m_var(new_i); ++new_i; } else x(m_system->dof_surface()) = -HUGE_VAL; if (m_system->ideq_electron() != no_equation) { x(m_system->dof_electron()) = m_var(new_i); ++new_i; } else x(m_system->dof_electron()) = -HUGE_VAL; for (index_t m: m_data->range_mineral()) { bool to_keep = true; for (const index_t& k: non_active_component) { if (m_data->nu_mineral(m, k) != 0.0) to_keep = false; } if (to_keep) { x(m_system->dof_mineral(m)) =m_var(new_i); ++new_i; } else { x(m_system->dof_mineral(m)) = 0.0; } } } } // PCFM // ---- void AdimensionalSystemSolver::run_pcfm(Vector &x) { DEBUG << "Start PCFM initialization."; // we set up the true variable set_true_variable_vector(x); // The residual is computed to have some point of comparison Vector residuals(m_system->total_variables()); residuals.setZero(); m_system->get_residuals(m_var, residuals); const scalar_t res_0 = residuals.norm(); // the pcfm iterations are executed AdimensionalSystemPCFM pcfm_solver(m_system); PCFMReturnCode retcode = pcfm_solver.solve(m_var); // Check the answer if (retcode < PCFMReturnCode::Success) { // small prograss is still good enough m_system->get_residuals(m_var, residuals); const scalar_t final_residual = residuals.norm(); DEBUG << "Final pcfm residuals : " << final_residual << " set_secondary_variables(m_var); } } // Initialisation of variables // --------------------------- void AdimensionalSystemSolver::initialise_variables( Vector& x, scalar_t volume_fraction_water, std::map log_molalities, std::map volume_fraction_minerals, scalar_t log_free_sorption_site_concentration ) { m_system->reasonable_starting_guess(x); if (volume_fraction_water < 0 or volume_fraction_water > 1) { WARNING << "Initial guess for the volume fraction of water is not between 0 and 1"; } x(m_system->dof_water()) = volume_fraction_water; for (auto pair: log_molalities) { index_t idc = m_data->get_id_component(pair.first); if (idc == no_species or idc == m_data->electron_index() or idc == m_data->water_index()) { throw std::invalid_argument("This is not an aqueous component : "+pair.first); } if (pair.second > 0) { WARNING << "Initial molality for : " << pair.first << "is bigger than 1 molal."; } x(m_system->dof_component(idc)) = pair.second; } for (auto pair: volume_fraction_minerals) { index_t idm = m_data->get_id_mineral(pair.first); if (idm == no_species ) { throw std::invalid_argument("This is not a mineral at equilibrium : "+pair.first); } if (pair.second < 0 or pair.second > 1) { WARNING << "Initial volume fraction for : " << pair.first << "is not between 0 and 1."; } x(m_system->dof_mineral(idm)) = pair.second; } if (log_free_sorption_site_concentration != 0.0) x(m_system->dof_surface()) = log_free_sorption_site_concentration; } void AdimensionalSystemSolver::initialise_variables(Vector& x, scalar_t volume_fraction_water, scalar_t log_molalities ) { m_system->reasonable_starting_guess(x); if (volume_fraction_water < 0 or volume_fraction_water > 1) { WARNING << "Initial guess for the volume fraction of water is not between 0 and 1"; } x(m_system->dof_water()) = volume_fraction_water; if (log_molalities > 0) { WARNING << "Initial molality for : " << log_molalities << "is bigger than 1 molal."; } x.segment(1, m_data->nb_component()-1).setConstant(log_molalities); } void AdimensionalSystemSolver::initialise_variables(Vector& x, scalar_t volume_fraction_water, scalar_t log_molalities, scalar_t log_free_sorption_site_concentration ) { initialise_variables(x, volume_fraction_water, log_molalities); x(m_system->dof_surface()) = log_free_sorption_site_concentration; } } // end namespace specmicp diff --git a/src/specmicp/adimensional/adimensional_system_solver.hpp b/src/specmicp/adimensional/adimensional_system_solver.hpp index e4780a3..84aabbe 100644 --- a/src/specmicp/adimensional/adimensional_system_solver.hpp +++ b/src/specmicp/adimensional/adimensional_system_solver.hpp @@ -1,158 +1,161 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLVER_HPP #define SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLVER_HPP #include "database.hpp" #include "adimensional_system.hpp" #include "adimensional_system_solver_structs.hpp" #include "utils/options_handler.hpp" #include //! \file adimensional_system_solver.hpp Solve a reduced system namespace specmicp { // forward declaration class AdimensionalSystemSolution; //! \brief Solve an adimensional system //! //! Take care of non-existing component in the system //! and restart the computation if necessary class AdimensionalSystemSolver: public OptionsHandler { public: using SystemPtr = std::shared_ptr; //! Default constructor //! //! Another constructor is necessary AdimensionalSystemSolver() {} AdimensionalSystemSolver(RawDatabasePtr data, const AdimensionalSystemConstraints& constraints, AdimensionalSystemSolverOptions options=AdimensionalSystemSolverOptions() ); AdimensionalSystemSolver(RawDatabasePtr data, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& previous_solution, AdimensionalSystemSolverOptions options=AdimensionalSystemSolverOptions() ); //! \brief solve the problem using initial guess x //! //! \param[in,out] x in -> initial guess, out -> solution //! \param init if true, the algorithm guess a starting point micpsolver::MiCPPerformance solve(Vector& x, bool init=false); //! \brief Return the system used for the computation SystemPtr get_system() {return m_system;} //! \brief Return the solution in a manageable form //! //! \param x The solution (complete set of the main variables) AdimensionalSystemSolution get_raw_solution(Vector& x); //! \brief Initialize the problem using the Positive continuous fraction method //! //! \sa specmicp::AdimensionalSystemPCFM void run_pcfm(Vector& x); //! \brief Custom initialisation of variables //! //! The amount compon //! \param[out] x The initial guess (complete set of the main variables) //! \param volume_fraction_water volume fraction of water //! \param log_molalities log_10 of the molalities for chosen aqueous component //! \param volume_fraction_minerals volume fraction of the minerals //! \param free_sorption_site_concentration concentration of free sorption site void initialise_variables(Vector& x, scalar_t volume_fraction_water, std::map log_molalities, std::map volume_fraction_minerals = {}, scalar_t log_free_sorption_site_concentration = 0 ); //! \brief Custom initialisation of variables //! //! The amount compon //! \param[out] x The initial guess (complete set of the main variables) //! \param volume_fraction_water volume fraction of water //! \param log_molalities log_10 of the molalities for all aqueous components void initialise_variables(Vector& x, scalar_t volume_fraction_water, scalar_t log_molalities ); //! \brief Custom initialisation of variables //! //! The amount compon //! \param[out] x The initial guess (complete set of the main variables) //! \param volume_fraction_water volume fraction of water //! \param log_molalities log_10 of the molalities for all aqueous components //! \param free_sorption_site_concentration concentration of free sorption site void initialise_variables(Vector& x, scalar_t volume_fraction_water, scalar_t log_molalities, scalar_t log_free_sorption_site_concentration ); private: //! \brief set up the true variable vector //! //! \param x The solution (complete set of the main variables) void set_true_variable_vector(const Vector& x); //! \brief set up the true solution vector //! //! add zero components //! \param x The solution (complete set of the main variables) void set_return_vector(Vector& x); //! \brief solve the problem micpsolver::MiCPPerformance solve_system(); RawDatabasePtr m_data; //! The raw database SystemPtr m_system; //! The system to solve Vector m_var; //! Copy of the solution vector (necessary in case of failing) }; //! \brief Solve a reduced system, function provided for convenience //! //! \param data_ptr the database //! \param constraints Constraints applied to the system //! \param options Options for the solver AdimensionalSystemSolution solve_equilibrium( RawDatabasePtr data_ptr, const AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolverOptions& options ); } // end namespace specmicp #endif // SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLVER_HPP diff --git a/src/specmicp/adimensional/adimensional_system_solver_structs.hpp b/src/specmicp/adimensional/adimensional_system_solver_structs.hpp index d77107f..655ea29 100644 --- a/src/specmicp/adimensional/adimensional_system_solver_structs.hpp +++ b/src/specmicp/adimensional/adimensional_system_solver_structs.hpp @@ -1,70 +1,73 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLVERSTRUCTS_HPP #define SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLVERSTRUCTS_HPP #include "common.hpp" #include "micpsolver/micpsolver_structs.hpp" #include "adimensional_system_structs.hpp" #include "physics/units.hpp" //! \file adimensional_system_solver_structs.hpp Options and conditions for AdimensionalSystemSolver namespace specmicp { //! \struct AdimensionalSystemSolverOptions //! \brief Options for the Equilibrium solver //! //! Most of the options are contained in the MiCP solver options or the AdimensionalSystem options struct AdimensionalSystemSolverOptions { micpsolver::MiCPSolverOptions solver_options; //!< Options of the MiCP solver AdimensionalSystemOptions system_options; //!< Options of the system bool allow_restart; //!< Allow the restarting if the problem failed the first part units::UnitsSet units_set; //!< Set of units bool use_pcfm; //!< If true use the pcfm method to initialize the problem bool force_pcfm; //!< Use pcfm before every trial AdimensionalSystemSolverOptions(): solver_options(), // default options of the solver system_options(), // default options of the system allow_restart(true), use_pcfm(false), force_pcfm(false) { // disable the descent condition check solver_options.disable_descent_direction(); } }; } // end namespace specmicp #endif //SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSOLVERSTRUCTS_HPP diff --git a/src/specmicp/adimensional/adimensional_system_structs.hpp b/src/specmicp/adimensional/adimensional_system_structs.hpp index ad79c33..fec53f9 100644 --- a/src/specmicp/adimensional/adimensional_system_structs.hpp +++ b/src/specmicp/adimensional/adimensional_system_structs.hpp @@ -1,256 +1,259 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSTRUCTS_HPP #define SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSTRUCTS_HPP #include "common.hpp" //! \file adimensional_system_structs.hpp Options and constraints for the AdimensionalSystem namespace specmicp { //! \struct AdimensionalSystemOptions //! \brief Options for the Adimensional Systems //! //! It is mainly about the secondary variables fixed-point iterations struct AdimensionalSystemOptions { bool non_ideality{true}; //!< Solve for non ideality index_t non_ideality_max_iter{10}; //!< Max iterations for the non ideality model scalar_t scaling_electron {0.0}; //!< Scaling the electron equation scalar_t non_ideality_tolerance{1e-8}; //!< Tolerance for non ideality scalar_t under_relaxation_factor{0.9}; //!< Under relaxation factor for the conservation of water scalar_t restart_concentration{-6}; //!< Log of the molality used to restart the computation scalar_t new_component_concentration{-4}; //!< Log_10 of the molality for a new component scalar_t start_non_ideality_computation{0.1}; //!< Factor to start the non-ideality computation scalar_t cutoff_total_concentration{1e-12}; //!< Cutoff for including components in the computation }; //! \enum AqueousComponentEquationType //! \brief Type of an aqueous component equation enum class AqueousComponentEquationType { NoEquation = no_equation, //!< Not an equation, component is not present in the system MassConservation, //!< Mass balance ChargeBalance, //!< M.B. replaced by charge balance FixedFugacity, //!< M.B. replaced by a fixed fugacity equation FixedActivity //!< M.B. replaced by a fixed activity equation }; //! \enum WaterEquationType //! \brief The type of the equation solved for the water enum class WaterEquationType { NoEquation = no_equation, //!< Amount of water is not solved MassConservation, //!< Water is conserved SaturatedSystem //!< System is saturated }; //! \struct FixedFugacityConstraint //! \brief Struct to contain information needed to solve a fix fugacity problem struct FixedFugacityConstraint { index_t id_gas; //!< Index of the fixed-fugacity gas index_t id_component; //!< Index of the corresponding component scalar_t log_value; //!< Log_10 of the fugacity FixedFugacityConstraint(index_t gas, index_t component, scalar_t logvalue) noexcept: id_gas(gas), id_component(component), log_value(logvalue) {} }; //! \struct FixedActivityConstraint //! \brief Struct to contain information needed to solve a fix activity problem. struct FixedActivityConstraint { index_t id_component; //!< Index of the fixed-activity component scalar_t log_value; //!< Log_10 of the activity FixedActivityConstraint(index_t component, scalar_t logvalue) noexcept: id_component(component), log_value(logvalue) {} }; //! \enum SurfaceEquationType //! \brief The model for surface sorption enum class SurfaceEquationType { NoEquation = no_equation, //!< Do not include surface sorption Equilibrium //!< Equilibrium model }; //! \struct SurfaceConstraint //! This struct contains the information to set-up the surface sorption model struct SurfaceConstraint { SurfaceEquationType model_type; //!< The model to use scalar_t concentration; //!< The total concentration of sorption sites //! \brief By default, we don't include surface sorption in the computation SurfaceConstraint() noexcept: model_type(SurfaceEquationType::NoEquation), concentration(0.0) {} //! \brief When a concentration is supplied, the surface sorption model is equilibrium SurfaceConstraint(scalar_t surface_concentration) noexcept: model_type(SurfaceEquationType::Equilibrium), concentration(surface_concentration) {} }; //! \enum ElectronEquationType the type of the equation for the electron enum class ElectronEquationType { NoEquation = no_equation, //!< Do not compute the concentration equation of the electron Equilibrium, //!< Set the concentration of electron to be 0 FixedpE //!< Activity of the electron is fixed }; //! \struct ElectronConstraint the constraint for the electron struct ElectronConstraint { ElectronEquationType equation_type{ElectronEquationType::NoEquation}; //!< The equation type scalar_t fixed_value; //!< The fixed value of pE if needed index_t species {no_species}; //!< In case of fixed pE, this is the reaction to use //! \brief By default we assume equilibrium ElectronConstraint() noexcept: equation_type(ElectronEquationType::Equilibrium), fixed_value(0.0) {} //! \brief When a value is provided, we assume that the pE is fixed ElectronConstraint(scalar_t pe_value, scalar_t aqueous_species) noexcept: equation_type(ElectronEquationType::FixedpE), fixed_value(pe_value), species(aqueous_species) {} }; //! \struct AdimensionalSystemConstraints //! \brief Struct to contains the "Boundary conditions" for the AdimensionalSystem struct AdimensionalSystemConstraints { Vector total_concentrations; //!< Total concentrations WaterEquationType water_equation{WaterEquationType::MassConservation}; //!< Water equation index_t charge_keeper{no_species}; //!< The equation for this component is replace by the charge balance bool saturated_system; //!> System is saturated - no gas phase std::vector fixed_fugacity_cs; //!< Contains information about fixed fugacity gas std::vector fixed_activity_cs; //!< Contains information about fixed activity component scalar_t inert_volume_fraction{ 0.0 }; //!< Volume fraction of inert solid (inert in the equilibrium computation) SurfaceConstraint surface_model{}; //!< Surface sorption model ElectronConstraint electron_constraint{}; //!< constraint for the electron AdimensionalSystemConstraints() {} AdimensionalSystemConstraints(const Vector& total_concs): total_concentrations(total_concs) {} //! \brief Set the total concentrations void set_total_concentrations(const Vector& total_concs) {total_concentrations = total_concs;} //! \brief Enable the conservation of water void enable_conservation_water() noexcept {water_equation = WaterEquationType::MassConservation;} //! \brief Disable the conservation of water void disable_conservation_water() noexcept {water_equation = WaterEquationType::NoEquation;} //! \brief The system is saturated void set_saturated_system() noexcept {water_equation = WaterEquationType::SaturatedSystem;} //! \brief Disable the surface sorption model void disable_surface_model() noexcept {surface_model.model_type = SurfaceEquationType::NoEquation;} //! \brief Enable the surface sorption model //! \param surface_sorption_model_concentration concentration of the surface sorption sites void enable_surface_model(scalar_t surface_sorption_model_concentration) noexcept { surface_model.model_type = SurfaceEquationType::Equilibrium; surface_model.concentration = surface_sorption_model_concentration; } //! \brief Set the charge keeper to 'component' //! //! \param component Index of the component (in the database) void set_charge_keeper(index_t component) noexcept { charge_keeper = component; } //! \brief Add a fixed fugacity gas condition //! //! \param constraint struct containing the information about a fixed-fugacity constraint void add_fixed_fugacity_gas(const FixedFugacityConstraint& constraint) { fixed_fugacity_cs.push_back(constraint); } //! \brief Add a fixed fugacity gas condition //! //! \param gas Index of the gas (in the database) //! \param component Index of the corresponding component (in the database) //! \param logvalue Log_10 of the fugacity void add_fixed_fugacity_gas(index_t gas, index_t component, scalar_t logvalue) noexcept { fixed_fugacity_cs.push_back(FixedFugacityConstraint(gas, component, logvalue)); } //! \brief Add a fixed activity component condition //! //! \param constraint struct containing the information about a fixed-activity constraint void add_fixed_activity_component(const FixedActivityConstraint& constraint) noexcept { fixed_activity_cs.push_back(constraint); } //! \brief Add a fixed activity component condition //! //! \param component Index of the corresponding component (in the database) //! \param log_value Log_10 of the activity void add_fixed_activity_component(index_t component, scalar_t log_value) noexcept { fixed_activity_cs.push_back(FixedActivityConstraint(component, log_value)); } //! \brief Set the inert volume fraction //! //! The volume fraction of the inert phase is used to offset the saturation. //! This inert phase may correspond to aggregates or solid phases governed by kinetics. //! //! \param value volume fraction of the inert phase void set_inert_volume_fraction(scalar_t value) noexcept { inert_volume_fraction = value; } // //! \brief Set the system at a fixed pE // void set_fixed_pe(scalar_t pe_value, index_t aqueous_species) noexcept { // electron_constraint = ElectronConstraint(pe_value, aqueous_species); // } }; } // end namespace specmicp #endif // SPECMICP_SPECMICP_ADIMENSIONALSYSTEMSTRUCTS_HPP diff --git a/src/specmicp/adimensional/equilibrium_curve.cpp b/src/specmicp/adimensional/equilibrium_curve.cpp index 5e898c2..2168080 100644 --- a/src/specmicp/adimensional/equilibrium_curve.cpp +++ b/src/specmicp/adimensional/equilibrium_curve.cpp @@ -1,93 +1,96 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "equilibrium_curve.hpp" #include "adimensional_system_solver.hpp" #include "utils/log.hpp" #define INITIALIZE true #define DONT_INITIALIZE false namespace specmicp { void EquilibriumCurve::solve_first_problem() { AdimensionalSystemSolver solver(m_data, m_constraints, m_solver_options); m_current_perf = solver.solve(m_solution_vector, INITIALIZE); if (m_current_perf.return_code <= micpsolver::MiCPSolverReturnCode::NotConvergedYet) { error_handling("Failed to solve first problem, return code : " + std::to_string((int) m_current_perf.return_code) + "."); } m_current_solution = solver.get_raw_solution(m_solution_vector); } void EquilibriumCurve::solve_problem() { AdimensionalSystemSolver solver(m_data, m_constraints, m_current_solution, m_solver_options); m_current_perf = solver.solve(m_solution_vector, DONT_INITIALIZE); if (m_current_perf.return_code <= micpsolver::MiCPSolverReturnCode::NotConvergedYet) { error_handling("Failed to solve problem, return code : " + std::to_string((int) m_current_perf.return_code) + "."); } m_current_solution = solver.get_raw_solution(m_solution_vector); } void EquilibriumCurve::error_handling(std::string msg) const { ERROR << msg; throw std::runtime_error(msg); } void EquilibriumCurve::set_problem() { update_problem(); } void EquilibriumCurve::post_processing() { output(); } void EquilibriumCurve::run_step() { set_problem(); solve_problem(); post_processing(); } } // end namespace specmicp #undef INITIALIZE #undef DONT_INITIALIZE diff --git a/src/specmicp/adimensional/equilibrium_curve.hpp b/src/specmicp/adimensional/equilibrium_curve.hpp index 9773b8e..6e2a0ab 100644 --- a/src/specmicp/adimensional/equilibrium_curve.hpp +++ b/src/specmicp/adimensional/equilibrium_curve.hpp @@ -1,139 +1,142 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPECMICP_EQUILIBRIUMCURVE_HPP #define SPECMICP_SPECMICP_EQUILIBRIUMCURVE_HPP #include "common.hpp" #include "database.hpp" #include "adimensional_system_solver_structs.hpp" #include "adimensional_system_solution.hpp" //! \file equilibrium_curve.hpp ABC to compute a reaction path namespace specmicp { //! \brief Abstract Base Class to compute an equilibrium curve //! //! class EquilibriumCurve { public: EquilibriumCurve() {} EquilibriumCurve(RawDatabasePtr database, AdimensionalSystemConstraints constraints ): m_data(database), m_constraints(constraints) {} //! \brief Run one step of the equilibrium curve void run_step(); //! \brief Return the raw database RawDatabasePtr database() const {return m_data;} //! \brief Return the current solution const AdimensionalSystemSolution& current_solution() const { return m_current_solution; } //! \brief Return the current solution vector Vector& solution_vector() { return m_solution_vector; } //! \brief Return the current MiCPsolver performance const micpsolver::MiCPPerformance& solver_performance() const { return m_current_perf; } //! \brief Return a const reference to the solver options const AdimensionalSystemSolverOptions& solver_options() const { return m_solver_options; } //! \brief Return a const reference to the BC of AdimensionalSystem const AdimensionalSystemConstraints& constraints() const { return m_constraints; } //! \brief update the problem; virtual void update_problem() = 0; //! \brief Output - do nothing by default virtual void output() {} //! \brief How to handle an error virtual void error_handling(std::string msg) const; //! \brief Solve the first problem void solve_first_problem(); protected: //! \brief Set the database void set_database(RawDatabasePtr the_database) { m_data =the_database; } //! \brief Read-write reference to the conditions AdimensionalSystemConstraints& constraints() { return m_constraints; } //! \brief Read-write reference to the options of AdimensionalSystemSolver AdimensionalSystemSolverOptions& solver_options() { return m_solver_options; } //! \brief Input the first solution void initialize_solution(const AdimensionalSystemSolution& init) { m_current_solution = init; } private: //! \brief Set the problem, according user input void set_problem(); //! \brief Solve the problem //! //! May fail, call error_handling void solve_problem(); //! \brief Post processing of the data void post_processing(); RawDatabasePtr m_data; AdimensionalSystemConstraints m_constraints; AdimensionalSystemSolverOptions m_solver_options; AdimensionalSystemSolution m_current_solution; micpsolver::MiCPPerformance m_current_perf; Vector m_solution_vector; }; } // end namespace specmicp #endif // SPECMICP_SPECMICP_EQUILIBRIUMCURVE_HPP diff --git a/src/specmicp/adimensional_kinetics/kinetic_model.hpp b/src/specmicp/adimensional_kinetics/kinetic_model.hpp index 90d6edd..d7ff33e 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_model.hpp +++ b/src/specmicp/adimensional_kinetics/kinetic_model.hpp @@ -1,82 +1,85 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPECMICP_ADIMKINETICS_KINETICMODEL_HPP #define SPECMICP_SPECMICP_ADIMKINETICS_KINETICMODEL_HPP #include "common.hpp" #include "kinetic_variables.hpp" namespace specmicp { namespace kinetics { // \brief Base class for a kinetic model class AdimKineticModel { public: AdimKineticModel() {} AdimKineticModel(const std::vector& list_species): m_list_species(list_species) {} virtual ~AdimKineticModel() {} //! \brief Return the number of kinetic minerals included in the problem index_t get_neq() {return m_list_species.size();} //! \brief Compute the kinetic rates and store them in dydt virtual void compute_rate( scalar_t t, const Vector& y, AdimKineticVariables& variables, Vector& dydt ) = 0; void add_equation(index_t species) {m_list_species.push_back(species);} //! \brief Index of species corresponding to equation 'id_equation' index_t index_species(index_t id_equation) {return m_list_species[id_equation];} //! \brief Iterator over the species vector std::vector::iterator species_begin() {return m_list_species.begin();} std::vector::iterator species_end() {return m_list_species.end();} private: std::vector m_list_species; }; } // end namespace kinetics } // end namespace specmicp #endif //SPECMICP_SPECMICP_ADIMKINETICS_KINETICMODEL_HPP diff --git a/src/specmicp/adimensional_kinetics/kinetic_system.cpp b/src/specmicp/adimensional_kinetics/kinetic_system.cpp index a933a78..23bc10b 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_system.cpp +++ b/src/specmicp/adimensional_kinetics/kinetic_system.cpp @@ -1,107 +1,110 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "kinetic_system.hpp" #include "kinetic_model.hpp" #include "specmicp/adimensional/adimensional_system_solver.hpp" #include "utils/log.hpp" namespace specmicp { namespace kinetics { void AdimKineticSystem::update_total_concentrations(const Vector& y) { //Vector y_temp = y.cwiseMax(Vector::Zero(y.rows())); Vector update_minerals = (y - m_variables.concentration_minerals()); m_variables.total_concentrations() = m_variables.total_concentrations_initial(); for (auto it=m_model->species_begin(); it!=m_model->species_end(); ++it) { for (index_t component: m_data->range_component()) { if (m_data->nu_mineral_kinetic(*it, component) == 0.0) continue; m_variables.total_concentration(component) -= m_data->nu_mineral_kinetic(*it, component)*update_minerals(it-m_model->species_begin()); } } } void AdimKineticSystem::update_to_new_initial_condition(const Vector& y, scalar_t dt) { update_total_concentrations(y); m_variables.rate_components() += ( m_variables.total_concentrations() - m_variables.total_concentrations_initial() )/dt; m_variables.concentration_minerals() = y; m_variables.total_concentrations_initial() = m_variables.total_concentrations(); } void AdimKineticSystem::compute_rates(scalar_t t, const Vector& y, Vector& dydt) { m_model->compute_rate(t, y, m_variables, dydt); } void AdimKineticSystem::compute_equilibrium( AdimensionalSystemConstraints& constraints, AdimensionalSystemSolverOptions& options) { AdimensionalSystemSolver solver; Vector variables; specmicp::micpsolver::MiCPPerformance perf; constraints.total_concentrations = m_variables.total_concentrations(); if (m_variables.equilibrium_solution().is_valid) { solver = AdimensionalSystemSolver(m_data, constraints, m_variables.equilibrium_solution(), options); variables = m_variables.equilibrium_solution().main_variables; perf = solver.solve(variables); } else { solver = AdimensionalSystemSolver(m_data, constraints, options); perf = solver.solve(variables, true); } //std::cout << variables << std::endl; if ((int) perf.return_code < 0) { ERROR << "Failed to solve the system ! Error code " << (int) perf.return_code; } m_variables.update_equilibrium_solution(solver.get_raw_solution(variables)); } } // end namespace kinetics } // end namespace specmicp diff --git a/src/specmicp/adimensional_kinetics/kinetic_system.hpp b/src/specmicp/adimensional_kinetics/kinetic_system.hpp index d872f03..346557a 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_system.hpp +++ b/src/specmicp/adimensional_kinetics/kinetic_system.hpp @@ -1,119 +1,122 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEM_HPP #define SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEM_HPP #include #include "common.hpp" #include "database.hpp" #include "kinetic_variables.hpp" #include "specmicp/adimensional/adimensional_system_solver_structs.hpp" namespace specmicp { namespace kinetics { class AdimKineticModel; //! \brief Kinetics System, //! //! Wrapper for a kinetic model class AdimKineticSystem { public: AdimKineticSystem( std::shared_ptr model, const Vector& total_concentrations, const Vector& mineral_concentrations, AdimensionalSystemConstraints& constraints, RawDatabasePtr database ): m_data(database), m_model(model), m_constraints(constraints), m_variables(total_concentrations, mineral_concentrations) {} AdimKineticSystem( std::shared_ptr model, const Vector& total_concentrations, const Vector& mineral_concentrations, AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& equilibrium_solution, RawDatabasePtr database ): m_data(database), m_model(model), m_constraints(constraints), m_variables(total_concentrations, mineral_concentrations, equilibrium_solution) {} //! \brief Compute the kinetics rates to be solved //! //! Use the kinetic model provided by the user void compute_rates(scalar_t x, const Vector& y, Vector& dydt); //! \brief Compute the equilibrium state of the solution void compute_equilibrium( AdimensionalSystemConstraints& constraints, AdimensionalSystemSolverOptions& options ); //! \brief Update the total concentrations //! //! \param y vector of variables (mols of minerals) void update_total_concentrations(const Vector& y); void update_to_new_initial_condition(const Vector& y, scalar_t dt); //! \brief Right Hand side function for the integrator void rhs(scalar_t x, const Vector& y, Vector& dydt, AdimensionalSystemSolverOptions& options) { update_total_concentrations(y); compute_equilibrium(m_constraints, options); compute_rates(x, y, dydt); } AdimKineticVariables& variables() {return m_variables;} AdimensionalSystemConstraints& constraints() {return m_constraints;} private: RawDatabasePtr m_data; std::shared_ptr m_model; AdimensionalSystemConstraints m_constraints; AdimKineticVariables m_variables; }; } // end namespace kinetics } // end namespace specmicp #endif //SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEM_HPP diff --git a/src/specmicp/adimensional_kinetics/kinetic_system_euler_solver.cpp b/src/specmicp/adimensional_kinetics/kinetic_system_euler_solver.cpp index 28081cf..42a2c32 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_system_euler_solver.cpp +++ b/src/specmicp/adimensional_kinetics/kinetic_system_euler_solver.cpp @@ -1,63 +1,66 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "kinetic_system_euler_solver.hpp" #include "kinetic_model.hpp" #include "odeint/runge_kutta_step.hpp" #include namespace specmicp { namespace kinetics { void AdimKineticSystemEulerSolver::solve(scalar_t dt, scalar_t total) { double t = 0.0; Vector y = m_system.variables().concentration_minerals(); Vector dydx(y.rows()); dydx.setZero(); while (t < total) { m_system.rhs(t, y, dydx, get_options().speciation_options); y += dt*dydx; m_system.update_to_new_initial_condition(y, dt); t += dt; if (t+dt > total) dt =(total - t); } m_system.update_total_concentrations(y); m_system.compute_equilibrium(m_system.constraints(), get_options().speciation_options); } } // end namespace kinetics } // end namespace specmicp diff --git a/src/specmicp/adimensional_kinetics/kinetic_system_euler_solver.hpp b/src/specmicp/adimensional_kinetics/kinetic_system_euler_solver.hpp index 147f0d2..177d16a 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_system_euler_solver.hpp +++ b/src/specmicp/adimensional_kinetics/kinetic_system_euler_solver.hpp @@ -1,83 +1,86 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMEULERSOLVER_HPP #define SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMEULERSOLVER_HPP #include "kinetic_system.hpp" #include "kinetic_system_solver_structs.hpp" #include "utils/options_handler.hpp" namespace specmicp { namespace kinetics { class AdimKineticModel; class AdimKineticSystemEulerSolver: public OptionsHandler { public: AdimKineticSystemEulerSolver( std::shared_ptr model, const Vector& total_concentrations, const Vector& mineral_concentration, AdimensionalSystemConstraints& constraints, RawDatabasePtr database ): m_current_dt(-1), m_system(model, total_concentrations, mineral_concentration, constraints, database) {} AdimKineticSystemEulerSolver( std::shared_ptr model, const Vector& total_concentrations, const Vector& mineral_concentration, AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& equilibrium_solution, RawDatabasePtr database ): m_current_dt(-1), m_system(model, total_concentrations, mineral_concentration, constraints, equilibrium_solution, database) {} void solve(scalar_t dt, scalar_t total); scalar_t current_dt() {return m_current_dt;} AdimKineticVariables& variables() {return m_system.variables();} private: scalar_t m_current_dt; AdimKineticSystem m_system; }; } // end namespace kinetics } // end namespace specmicp #endif //SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMEULERSOLVER_HPP diff --git a/src/specmicp/adimensional_kinetics/kinetic_system_solver.cpp b/src/specmicp/adimensional_kinetics/kinetic_system_solver.cpp index 36fc4bd..172a6bd 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_system_solver.cpp +++ b/src/specmicp/adimensional_kinetics/kinetic_system_solver.cpp @@ -1,79 +1,82 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "kinetic_system_solver.hpp" #include "kinetic_model.hpp" #include "odeint/runge_kutta_step.hpp" #include namespace specmicp { namespace kinetics { void AdimKineticSystemSolver::solve(scalar_t dt, scalar_t total) { double t = 0.0; Vector y = m_system.variables().concentration_minerals(); Vector dydx(y.rows()); dydx.setZero(); m_system.rhs(t, y, dydx, get_options().speciation_options); odeint::rhs_f rhs = std::bind(std::mem_fn(&AdimKineticSystem::rhs), m_system, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, get_options().speciation_options); //odeint::CashKarpStep driver = odeint::get_cash_karp_step(rhs); odeint::DormandPrinceStep driver = odeint::get_dormand_prince_step(rhs); odeint::StepLength stepl(dt, total); int cnt = 0; while (t < total) { driver.rk_step(y, dydx, t, stepl); m_system.update_to_new_initial_condition(y, stepl.did); cnt +=1; scalar_t remaining = stepl.remaining(t); if (remaining == 0.0) break; if (stepl.next > remaining) stepl.next = remaining; stepl.get_next(); m_current_dt = stepl.test; } m_system.update_total_concentrations(y); m_system.compute_equilibrium(m_system.constraints(), get_options().speciation_options); } } // end namespace kinetics } // end namespace specmicp diff --git a/src/specmicp/adimensional_kinetics/kinetic_system_solver.hpp b/src/specmicp/adimensional_kinetics/kinetic_system_solver.hpp index a8d8cea..f1b408e 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_system_solver.hpp +++ b/src/specmicp/adimensional_kinetics/kinetic_system_solver.hpp @@ -1,83 +1,86 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMSOLVER_HPP #define SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMSOLVER_HPP #include "kinetic_system.hpp" #include "kinetic_system_solver_structs.hpp" #include "utils/options_handler.hpp" namespace specmicp { namespace kinetics { class AdimKineticModel; class AdimKineticSystemSolver: public OptionsHandler { public: AdimKineticSystemSolver( std::shared_ptr model, const Vector& total_concentrations, const Vector& mineral_moles, AdimensionalSystemConstraints& constraints, RawDatabasePtr database ): m_current_dt(-1), m_system(model, total_concentrations, mineral_moles, constraints, database) {} AdimKineticSystemSolver( std::shared_ptr model, const Vector& total_concentrations, const Vector& mineral_moles, AdimensionalSystemConstraints& constraints, const AdimensionalSystemSolution& equilibrium_solution, RawDatabasePtr database ): m_current_dt(-1), m_system(model, total_concentrations, mineral_moles, constraints, equilibrium_solution, database) {} void solve(scalar_t dt, scalar_t total); scalar_t current_dt() {return m_current_dt;} AdimKineticVariables& variables() {return m_system.variables();} private: scalar_t m_current_dt; AdimKineticSystem m_system; }; } // end namespace kinetics } // end namespace specmicp #endif //SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMSOLVER_HPP diff --git a/src/specmicp/adimensional_kinetics/kinetic_system_solver_structs.hpp b/src/specmicp/adimensional_kinetics/kinetic_system_solver_structs.hpp index 8d0c604..6e9bace 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_system_solver_structs.hpp +++ b/src/specmicp/adimensional_kinetics/kinetic_system_solver_structs.hpp @@ -1,49 +1,52 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMSOLVERSTRUCTS #define SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMSOLVERSTRUCTS #include "specmicp/adimensional/adimensional_system_solver_structs.hpp" #include "odeint/runge_kutta_step_structs.hpp" namespace specmicp { namespace kinetics { struct AdimKineticSystemSolverOptions { odeint::EmbeddedRungeKuttaStepOptions rk_options; AdimensionalSystemSolverOptions speciation_options; }; } // end namespace kinetics } // end namespace specmicp #endif // SPECMICP_SPECMICP_ADIMKINETICS_KINETICSYSTEMSOLVERSTRUCTS diff --git a/src/specmicp/adimensional_kinetics/kinetic_variables.hpp b/src/specmicp/adimensional_kinetics/kinetic_variables.hpp index 4861058..5d6c05c 100644 --- a/src/specmicp/adimensional_kinetics/kinetic_variables.hpp +++ b/src/specmicp/adimensional_kinetics/kinetic_variables.hpp @@ -1,136 +1,139 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPECMICP_ADIMKINETICS_KINETICVARIABLES_HPP #define SPECMICP_SPECMICP_ADIMKINETICS_KINETICVARIABLES_HPP #include "common.hpp" #include "database.hpp" #include "specmicp/adimensional/adimensional_system_solution.hpp" namespace specmicp { namespace kinetics { //! \brief Variables used in a kinetic computation class AdimKineticVariables { public: AdimKineticVariables( const Vector& total_concentrations, const Vector& mineral_concentration ): m_mineral_kinetics(mineral_concentration), m_total_concentrations_initial(total_concentrations), m_total_concentrations(total_concentrations), m_rate(Vector::Zero(total_concentrations.rows())) {} AdimKineticVariables( const Vector& total_concentrations, const Vector& mineral_concentration, const AdimensionalSystemSolution& equilibrium_solution ): m_mineral_kinetics(mineral_concentration), m_total_concentrations_initial(total_concentrations), m_total_concentrations(total_concentrations), m_rate(Vector::Zero(total_concentrations.rows())), m_equilibrium_solution(equilibrium_solution) {} //! \brief Return the number of species considered in the kinetics computation index_t get_neq() {return m_mineral_kinetics.rows();} // Concentration of minerals // --------------------------- //! \brief Return mole number of mineral "mineral kinetic" scalar_t concentration_mineral(index_t mineral_kinetic) const {return m_mineral_kinetics(mineral_kinetic);} //! \brief Return a const reference to the vector of moles number const Vector& concentration_minerals() const {return m_mineral_kinetics;} //! \brief Return a reference to the vector of moles number Vector& concentration_minerals() {return m_mineral_kinetics;} // Total concentrations // -------------------- //! \brief Return the total concentration (at equilibrium) of 'component' scalar_t total_concentration(index_t component) const {return m_total_concentrations(component);} //! \brief Return the total concentration (at equilibrium) of 'component' scalar_t& total_concentration(index_t component) {return m_total_concentrations(component);} //! \brief Return a const reference to the total concentration (at equilibrium) vector const Vector& total_concentrations() const {return m_total_concentrations;} //! \brief Return a reference to the total concentration at equilibrium vector Vector& total_concentrations() {return m_total_concentrations; } // Initial total concentrations // ---------------------------- //! \brief Return the total concentration (at equilibrium) of 'component' scalar_t total_concentration_initial(index_t component) const { return m_total_concentrations_initial(component);} //! \brief Return a const reference to the total concentration (at equilibrium) vector const Vector& total_concentrations_initial() const {return m_total_concentrations_initial;} //! \brief Return a reference to the total concentration at equilibrium vector Vector& total_concentrations_initial() {return m_total_concentrations_initial; } // Rates // ----- //! \brief Return the value of the flux for 'component' scalar_t rate_component(index_t component) const { return m_rate(component); } //! \brief Return a const reference to the flux vector const Vector& rate_components() const {return m_rate;} //! \brief Return a reference to the flux vector Vector& rate_components() {return m_rate;} //! \brief reset the rates void reset_rate() {m_rate.setZero();} // Equilibrium // ------------ //! \brief Const Reference to the equilibrium state const AdimensionalSystemSolution& equilibrium_solution() const {return m_equilibrium_solution;} //! \brief Reference to the equilibrium State AdimensionalSystemSolution& equilibrium_solution() {return m_equilibrium_solution;} //! \brief Update the equilibrium state void update_equilibrium_solution(const AdimensionalSystemSolution& other) {m_equilibrium_solution = other;} private: Vector m_mineral_kinetics; //!< Number of moles of minerals at equilibrium Vector m_total_concentrations_initial; //!< Initial total concentrations at equilibrium Vector m_total_concentrations; //!< total concentration at equilibrium, Vector m_rate; AdimensionalSystemSolution m_equilibrium_solution; //!< Current equilibrium state }; } // end namespace kinetics } // end namespace specmicp #endif // SPECMICP_SPECMICP_KINETICS_KINETICVARIABLES_HPP diff --git a/src/specmicp/problem_solver/dissolver.cpp b/src/specmicp/problem_solver/dissolver.cpp index 36ad73b..348e117 100644 --- a/src/specmicp/problem_solver/dissolver.cpp +++ b/src/specmicp/problem_solver/dissolver.cpp @@ -1,171 +1,174 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #include "dissolver.hpp" #include "formulation.hpp" #include "database/database.hpp" namespace specmicp { Vector Dissolver::dissolve(const Formulation& the_problem) { m_components_to_keep[0] = true; m_components_to_keep[1] = true; for (index_t component: m_database->range_aqueous_component()) { m_components_to_keep[component] = false; } m_total_concentration.setZero(); set_solvent(the_problem.mass_solution); for (auto it=the_problem.concentration_aqueous.begin(); it!=the_problem.concentration_aqueous.end(); ++it) { dissolve_aqueous(it->first, it->second, the_problem.mass_solution); } for (auto it=the_problem.amount_minerals.begin(); it!=the_problem.amount_minerals.end(); ++it) { dissolve_mineral(it->first, it->second); } keep_extra_components(the_problem.extra_components_to_keep); reduce_problem(); // Remove minerals if needed if (the_problem.minerals_to_keep.size() > 0) { database::Database(m_database).minerals_keep_only(the_problem.minerals_to_keep); } return m_total_concentration; } void Dissolver::set_solvent(scalar_t amount) { index_t idw = m_database->water_index(); specmicp_assert(idw != no_species and idw == 0); m_total_concentration(0) += amount/m_database->molar_mass_basis(idw, mass_unit()); m_components_to_keep[0] = true; } void Dissolver::dissolve_aqueous(std::string label, scalar_t concentration, scalar_t mass_solution) { index_t idaq = m_database->get_id_component(label); if (idaq != no_species) { m_total_concentration(idaq) += mass_solution*concentration; m_components_to_keep[idaq] = true; } else { index_t idsaq = m_database->get_id_aqueous(label); if (idsaq == no_species) { throw std::invalid_argument("Unknown species : " + label + "."); } for (index_t component: m_database->range_component()) { if (m_database->nu_aqueous(idsaq, component) == 0.0) continue; m_total_concentration(component) += m_database->nu_aqueous(idsaq, component)*mass_solution*concentration; m_components_to_keep[component] = true; } } } void Dissolver::dissolve_mineral(std::string label, scalar_t amount) { index_t id_mineral = m_database->get_id_mineral(label); if (id_mineral != no_species) { for (index_t component: m_database->range_component()) { if (m_database->nu_mineral(id_mineral, component) == 0.0) continue; m_total_concentration(component) += m_database->nu_mineral(id_mineral, component)*amount; m_components_to_keep[component] = true; } } else { index_t id_minkin = m_database->get_id_mineral_kinetic(label); if (id_minkin == no_species) { throw std::invalid_argument("Unknown mineral : " + label + "."); } for (index_t component: m_database->range_component()) { if (m_database->nu_mineral_kinetic(id_minkin, component) == 0.0) continue; m_total_concentration(component) += m_database->nu_mineral_kinetic(id_minkin, component)*amount; m_components_to_keep[component] = true; } } } void Dissolver::keep_extra_components(const std::vector& list_component_to_keep) { for (auto it:list_component_to_keep) { index_t idc = m_database->get_id_component(it); if (idc == no_species) { throw std::invalid_argument("Species '" + it + "' is not a component"); } m_components_to_keep[idc] = true; } } void Dissolver::reduce_problem() { std::vector to_remove; to_remove.reserve(m_database->nb_component()); index_t new_id = 0; Vector reduced_tot_conc(m_database->nb_component()); // Copy information for (index_t component: m_database->range_component()) { if (m_components_to_keep[component]) { reduced_tot_conc(new_id) = m_total_concentration(component); ++new_id; } else { to_remove.push_back(component); } } // Remove components from database database::Database(m_database).remove_components(to_remove); // Resize total concentrations reduced_tot_conc.conservativeResize(m_database->nb_component()); m_total_concentration = reduced_tot_conc; } } // end namespace specmicp diff --git a/src/specmicp/problem_solver/dissolver.hpp b/src/specmicp/problem_solver/dissolver.hpp index 94c06ec..8f7603e 100644 --- a/src/specmicp/problem_solver/dissolver.hpp +++ b/src/specmicp/problem_solver/dissolver.hpp @@ -1,81 +1,84 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPECMICP_PROBLEMSOLVER_DISSOLVER_HPP #define SPECMICP_SPECMICP_PROBLEMSOLVER_DISSOLVER_HPP #include "common.hpp" #include "database.hpp" #include "physics/units.hpp" namespace specmicp { class Formulation; //! \brief Return the total concentration of a given formulation class Dissolver: public units::UnitBaseClass { public: Dissolver(RawDatabasePtr the_database): m_database(the_database), m_total_concentration(the_database->nb_component()), m_components_to_keep(the_database->nb_component()) { m_total_concentration.setZero(); } //! \brief Dissolve the problem into the components //! //! Also simplify the database Vector dissolve(const Formulation& the_problem); //! \brief Return the total concentration vector Vector get_total_concentration() {return m_total_concentration;} private: void set_solvent(scalar_t amount); void dissolve_aqueous(std::string label, scalar_t concentration, scalar_t mass_solution); void dissolve_mineral(std::string label, scalar_t amount); void keep_extra_components(const std::vector& list_component_to_keep); void reduce_problem(); private: RawDatabasePtr m_database; Vector m_total_concentration; std::vector m_components_to_keep; }; } // end namespace specmicp #endif //SPECMICP_SPECMICP_PROBLEMSOLVER_DISSOLVER_HPP diff --git a/src/specmicp/problem_solver/formulation.hpp b/src/specmicp/problem_solver/formulation.hpp index 798af88..1dbfbed 100644 --- a/src/specmicp/problem_solver/formulation.hpp +++ b/src/specmicp/problem_solver/formulation.hpp @@ -1,109 +1,112 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPECMICP_PROBLEMSOLVER_FORMULATION_HPP #define SPECMICP_SPECMICP_PROBLEMSOLVER_FORMULATION_HPP #include "common.hpp" #include #include #include namespace specmicp { struct Formulation { //! \brief Mass of the solvent scalar_t mass_solution; //! \brief Contains the amount of each solid phase std::map concentration_aqueous; //! \brief Contains the amount of each solid phase //! included in the problem std::map amount_minerals; //! \brief Extra component to leave in the database //! //! All components not present in this list and with //! a total concentration of zero will be removed. std::vector extra_components_to_keep; //! \brief List of solid phase at equilibrium to keep in the computation //! //! Leave empty to keep all solid phases present in the database std::vector minerals_to_keep; //! \brief Set the mass of the solution void set_mass_solution(scalar_t mass) { mass_solution = mass; } //! \brief Add an aqueous species to the system //! //! \param label label of a component or a secondary species //! \param concentration in moles per volume unit void add_aqueous_species(const std::string& label, scalar_t concentration) { concentration_aqueous.insert(std::pair(label, concentration)); } //! \brief Add an aqueous species to the system //! //! \param label label of a component or a secondary species //! \param concentration in moles per volume unit void add_aqueous_species(std::string&& label, scalar_t concentration) { concentration_aqueous.emplace(std::move(label), concentration); } //! \brief Add a mineral to the system //! //! \param label label of a mineral at equilibrium or governed by kinetics //! \param concentration in moles per volume unit void add_mineral(const std::string& label, scalar_t concentration) { amount_minerals.insert(std::pair(label, concentration)); } //! \brief Add a mineral to the system //! //! \param label label of a mineral at equilibrium or governed by kinetics //! \param concentration in moles per volume unit void add_mineral(std::string&& label, scalar_t concentration) { amount_minerals.emplace(std::move(label), concentration); } //! \brief Keep a component in the database even if it doesn't exist in the initial composition void keep_component(const std::string& label) { extra_components_to_keep.push_back(label); } //! \brief Set the list of minerals at equilibrium void set_minerals_list(const std::vector& list_minerals_equilibrium) { minerals_to_keep = std::vector(list_minerals_equilibrium); } //! \brief Set the list of minerals at equilibrium void set_minerals_list(std::vector&& list_minerals_equilibrium) { minerals_to_keep = std::vector(std::move(list_minerals_equilibrium)); } }; } // end namespace specmicp #endif // SPECMICP_SPECMICP_PROBLEMSOLVER_FORMULATION_HPP diff --git a/src/utils/io/meshes.hpp b/src/utils/io/meshes.hpp index 0f71668..b97f5cd 100644 --- a/src/utils/io/meshes.hpp +++ b/src/utils/io/meshes.hpp @@ -1,63 +1,66 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_IO_MESHES_HPP #define SPECMICP_IO_MESHES_HPP #include #include #include "dfpm/meshes/mesh1d.hpp" #include "physics/units.hpp" #include "utils/io/units.hpp" namespace specmicp { namespace io { inline void print_mesh(std::ostream* output, mesh::Mesh1DPtr the_mesh, units::LengthUnit lenght_unit) { (*output) << "# dfpm mesh \n"; (*output) << "# units : " << length_unit_to_string(lenght_unit) << "\n"; (*output) << "Node\tDistance\tCell_volume" << std::endl; for (index_t node: the_mesh->range_nodes()) { (*output) << node << "\t" << the_mesh->get_position(node) << "\t" << the_mesh->get_volume_cell(node) << "\n"; } } inline void print_mesh(std::string filepath, mesh::Mesh1DPtr the_mesh, units::LengthUnit lenght_unit) { std::ofstream outfile(filepath); print_mesh(&outfile, the_mesh, lenght_unit); outfile.close(); } } // end namespace io } // end namespace specmicp #endif // SPECMICP_IO_MESHES_HPP diff --git a/src/utils/io/reactive_transport.hpp b/src/utils/io/reactive_transport.hpp index f9441e9..3923965 100644 --- a/src/utils/io/reactive_transport.hpp +++ b/src/utils/io/reactive_transport.hpp @@ -1,190 +1,193 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_IO_REACTMICP_HPP #define SPECMICP_IO_REACTMICP_HPP #include #include "reactmicp/solver/reactive_transport_solver_structs.hpp" #include "utils/timer.hpp" namespace specmicp { namespace io { //! \brief Print the header inline void print_reactmicp_header( std::ostream* output ); //! \brief Print the performance information of the reactive transport solver inline void print_reactmicp_performance_short( std::ostream* output, const reactmicp::solver::ReactiveTransportPerformance& perf ); //! \brief Print the timing information of the reactive transport solver inline void print_reactmicp_timer( std::ostream* output, const reactmicp::solver::ReactiveTransportTimer& timer ); //! \brief Return a literal version of a ReactiveTransportReturnCode inline std::string reactmicp_return_code_to_string( reactmicp::solver::ReactiveTransportReturnCode retcode); inline void print_reactmicp_header( std::ostream* output ) { (*output) << "// ================================== //\n" << "// //\n" << "// ReactMiCP //\n" << "// //\n" << "// ================================== //\n\n" << "A reactive transport solver based on SpecMiCP.\n" << "------------------------------------------- \n" << std::endl; } inline void print_reactmicp_performance_short( std::ostream* output, const reactmicp::solver::ReactiveTransportPerformance& perf ) { (*output) << "------------------------------------------- \n" << " Performance \n " << "------------------------------------------- \n\t" << " - Return code : " << reactmicp_return_code_to_string(perf.return_code) << "\n\t" << " - Residuals : " << perf.residuals << "\n\t" << " - Number of iterations : " << perf.nb_iterations << "\n" << "------------------------------------------- " << std::endl; } inline void print_reactmicp_timer( std::ostream* output, const reactmicp::solver::ReactiveTransportTimer& timer ) { (*output) << "------------------------------------------- \n" << "Time spent in each stagger \n" << "------------------------------------------- \n\t" << "- Transport : " << timer.transport_time << " s\n\t" << "- Chemistry : " << timer.chemistry_time << " s\n\t" << "- Upscaling : " << timer.upscaling_time << " s\n" << "-----------------------------------------" << std::endl; } inline void print_reactmicp_end( std::ostream* output, const Timer& total_timer, const reactmicp::solver::ReactiveTransportTimer& timer ) { scalar_t elapsed_s = total_timer.elapsed_time(); index_t hours = static_cast(elapsed_s) / 3600; index_t elapsed_minutes = elapsed_s - hours*3600; index_t minute = elapsed_minutes / 60; index_t seconds = elapsed_minutes - 60*minute; (*output) << " ====================================================== \n"; (*output) << "computation finished at " << total_timer.get_ctime_stop(); (*output) << " Duration of the computation : " << total_timer.elapsed_time() << " s" << "( " << hours << "h " << minute << "min " << seconds << "s )\n"; print_reactmicp_timer(output, timer); } inline void print_reactmicp_performance_long_header( std::ostream* output ) { (*output) << "Id\t T\t dt\t Return_code\t Iterations \t Residuals\t Time\t Transport_time\t Chemistry_time" << std::endl; } inline void print_reactmicp_performance_long( std::ostream* output, index_t cnt, scalar_t total, const reactmicp::solver::ReactiveTransportPerformance& perfs ) { (*output) << cnt << "\t " << total << "\t " << perfs.timestep << "\t " << (int) perfs.return_code << "\t " << perfs.nb_iterations << "\t " << perfs.residuals << "\t " << perfs.total_time << "\t" << perfs.transport_time << "\t" << perfs.chemistry_time << std::endl; } inline std::string reactmicp_return_code_to_string( reactmicp::solver::ReactiveTransportReturnCode retcode) { using RetCode = reactmicp::solver::ReactiveTransportReturnCode; switch (retcode) { case RetCode::ResidualMinimized: return "ResidualMinimized"; case RetCode::ErrorMinimized: return "ErrorMinimized"; default: switch (retcode) { case RetCode::StationaryPoint: return "StationaryPoint"; case RetCode::MaximumIterationsReached: return "MaximumIterationsReached"; case RetCode::GoodEnough: return "Good enough..."; case RetCode::TransportBypass: return "Transport Bypass"; case RetCode::TransportFailure: return "TransportFailure"; case RetCode::ChemistryFailure: return "ChemistryFailure"; case RetCode::UpscalingFailure: return "UpscalingFailure"; default: return "Unknow error code !"; } } } } // end namespace io } // end namespace specmicp #endif // SPECMICP_IO_REACTMICP_HPP diff --git a/src/utils/io/saturated_react.hpp b/src/utils/io/saturated_react.hpp index 4c0020d..ee92b31 100644 --- a/src/utils/io/saturated_react.hpp +++ b/src/utils/io/saturated_react.hpp @@ -1,197 +1,200 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_IO_SATURATEDREACT_HPP #define SPECMICP_IO_SATURATEDREACT_HPP #include #include #include "utils/io/units.hpp" //#include "reactmicp/systems/saturated_react/variablesfwd.hpp" #include "reactmicp/systems/saturated_react/variables.hpp" #include #include using namespace specmicp::reactmicp::systems::satdiff; namespace specmicp { namespace io { static constexpr char field_sep = '\t'; static constexpr char comment = '#'; void print_csv_header(std::ostream* ofile) { std::time_t time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); (*ofile) << comment << " - ReactMiCP - " << std::ctime(&time); } void print_components_total_aqueous_concentration( RawDatabasePtr the_database, SaturatedVariablesPtr variables, mesh::Mesh1DPtr the_mesh, const units::UnitsSet& units_set, std::ostream* ofile ) { print_csv_header(ofile); (*ofile) << comment << "units : mol/" << io::volume_unit_to_string(units_set.length) << std::endl; (*ofile) << "Position"; for (index_t component: the_database->range_aqueous_component()) { (*ofile) << field_sep << the_database->get_label_component(component); } (*ofile) << std::endl; for (index_t node: the_mesh->range_nodes()) { (*ofile) << the_mesh->get_position(node); for (index_t component: the_database->range_aqueous_component()) { (*ofile) << field_sep << variables->aqueous_concentration(node, component); } (*ofile) << std::endl; } } void print_components_total_aqueous_concentration( RawDatabasePtr the_database, SaturatedVariablesPtr variables, mesh::Mesh1DPtr the_mesh, const units::UnitsSet& units_set, const std::string& filepath ) { std::ofstream ofile(filepath); print_components_total_aqueous_concentration(the_database, variables, the_mesh, units_set, &ofile); ofile.close(); } void print_components_total_solid_concentration( RawDatabasePtr the_database, SaturatedVariablesPtr variables, mesh::Mesh1DPtr the_mesh, const units::UnitsSet& units_set, std::ostream* ofile ) { print_csv_header(ofile); (*ofile) << comment << "units : mol/" << io::volume_unit_to_string(units_set.length) << std::endl; (*ofile) << "Position"; for (index_t component: the_database->range_aqueous_component()) { (*ofile) << field_sep << the_database->get_label_component(component); } (*ofile) << std::endl; for (index_t node: the_mesh->range_nodes()) { (*ofile) << the_mesh->get_position(node); for (index_t component: the_database->range_aqueous_component()) { (*ofile) << field_sep << variables->solid_concentration(node, component); } (*ofile) << std::endl; } } void print_components_total_solid_concentration( RawDatabasePtr the_database, SaturatedVariablesPtr variables, mesh::Mesh1DPtr the_mesh, const units::UnitsSet& units_set, const std::string& filepath ) { std::ofstream ofile(filepath); print_components_total_solid_concentration(the_database, variables, the_mesh, units_set, &ofile); ofile.close(); } void print_minerals_profile( RawDatabasePtr the_database, SaturatedVariablesPtr variables, mesh::Mesh1DPtr the_mesh, std::ostream* ofile ) { print_csv_header(ofile); (*ofile) << "Position"; for (index_t mineral: the_database->range_mineral()) { (*ofile) << field_sep << the_database->get_label_mineral(mineral); } (*ofile) << field_sep << "Porosity"; (*ofile) << field_sep << "pH"; (*ofile) << std::endl; for (index_t node: the_mesh->range_nodes()) { (*ofile) << the_mesh->get_position(node); AdimensionalSystemSolutionExtractor extractor(variables->equilibrium_solution(node), the_database, units::UnitsSet()); for (index_t mineral: the_database->range_mineral()) { (*ofile) << field_sep << extractor.volume_fraction_mineral(mineral); } (*ofile) << field_sep << variables->porosity(node); (*ofile) << field_sep << extractor.pH(); (*ofile) << std::endl; } } void print_minerals_profile( RawDatabasePtr the_database, SaturatedVariablesPtr variables, mesh::Mesh1DPtr the_mesh, const std::string& filepath ) { std::ofstream ofile(filepath); print_minerals_profile( the_database, variables, the_mesh, &ofile ); ofile.close(); } } // end namespace io } // end namespace specmicp #endif // SPECMICP_IO_SATURATEDREACT_HPP diff --git a/src/utils/io/units.hpp b/src/utils/io/units.hpp index 3c98580..62193c4 100644 --- a/src/utils/io/units.hpp +++ b/src/utils/io/units.hpp @@ -1,63 +1,66 @@ -#ifndef SPECMICP_IO_UNITS_HPP -#define SPECMICP_IO_UNITS_HPP - -#include -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ +#ifndef SPECMICP_IO_UNITS_HPP +#define SPECMICP_IO_UNITS_HPP + +#include #include "physics/units.hpp" namespace specmicp { namespace io { std::string length_unit_to_string(units::LengthUnit length_u) { switch (length_u) { case units::LengthUnit::meter: return "m"; break; case units::LengthUnit::decimeter: return "dm"; break; case units::LengthUnit::centimeter: return "cm"; break; } } std::string volume_unit_to_string(units::LengthUnit length_u) { return length_unit_to_string(length_u) + "^3"; } } // end namespace io } // end namespace specmicp #endif // SPECMICP_IO_UNITS_HPP diff --git a/src/utils/log.hpp b/src/utils/log.hpp index 295033b..4cc665e 100644 --- a/src/utils/log.hpp +++ b/src/utils/log.hpp @@ -1,170 +1,173 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_UTILS_LOG_HPP #define SPECMICP_UTILS_LOG_HPP #include //! \file log.hpp logger namespace specmicp { namespace logger { //! \enum LogLevel the different log level //! //! If changed, the function to_string must also be changed enum LogLevel {Critical, //!< Error that should lead to abortion Error, //!< Error Warning, //!< Warnings Info, //!< May be worth mentionning, not worth listening... Debug, //!< (Relevant) Debugging information Spam //!< How is your life ? ususally contains large debugging information such as the variables vector }; //! \brief Format the log level into a string inline std::string to_string(LogLevel); /*! \brief A log message * * The message is written during the destruction of the Log object. * The stream which contain the message is accessed with the member get(Level) */ template class Log { public: //! Constructor Log() {} //! Destructor - Output the message ~Log(); //! \brief Return the steam so we can write the message std::ostringstream& get(LogLevel level); //! \brief Return the report level static LogLevel& ReportLevel(){ static LogLevel report_level = Debug; return report_level; } protected: std::ostringstream msg; //!< the actual message private: // this are hidden on purpose, no need Log(Log&); Log& operator=(Log&); }; template std::ostringstream& Log::get(LogLevel level) { msg << to_string(level) << " : "; return msg; } template Log::~Log() { outputPolicy::output(msg.str()); } //! \brief Output Policy to use for logging class ErrFile { public: //! \brief Return a pointer to the stream we want to write in static std::ostream*& stream(); //! \brief Output the message to the stream static void output(const std::string& msg); }; inline std::ostream*& ErrFile::stream() { static std::ostream* stream = nullptr; return stream; } inline void ErrFile::output(const std::string &msg) { std::ostream* out = stream(); (*out) << msg << std::endl; out->flush(); } inline std::string to_string(LogLevel level) { static const char* list_level[] = {"CRITICAL", "ERROR", "Warning", "info", "debug", "spam"}; return list_level[static_cast(level)]; } } // end namespace logger //! \brief Standard logger type using stdlog = logger::Log; //! \brief Initialize the logger //! //! \param out the output stream //! \param level the output level inline void init_logger(std::ostream* out, specmicp::logger::LogLevel level) { logger::ErrFile::stream() = out; stdlog::ReportLevel() = level; } //! \brief Filter logs to stdlog #define FILTER(level) \ if (level > stdlog::ReportLevel() || logger::ErrFile::stream() == nullptr) ;\ else stdlog().get(level) //! \brief Spam log to stdlog #define SPAM FILTER(logger::Spam) //! \brief Debug log to stdlog #define DEBUG FILTER(logger::Debug) //! \brief Info log to stdlog #ifdef INFO #undef INFO #endif #define INFO FILTER(logger::Info) //! \brief Warning log to stdlog #define WARNING FILTER(logger::Warning) //! \brief Error log to stdlog #define ERROR FILTER(logger::Error) //! \brief Critical log to stdlog #define CRITICAL FILTER(logger::Critical) } // end namespace specmicp #endif // SPECMICP_UTILS_LOG_HPP diff --git a/src/utils/moving_average.hpp b/src/utils/moving_average.hpp index 8c4fbdd..690ff62 100644 --- a/src/utils/moving_average.hpp +++ b/src/utils/moving_average.hpp @@ -1,80 +1,83 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_UTILS_MOVINGAVERAGE_HPP #define SPECMICP_UTILS_MOVINGAVERAGE_HPP #include "common.hpp" namespace specmicp { namespace utils { //! \brief Exponential moving average //! //! https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average //! //! @param alpha coefficient between 0 and 1 //! @param init initial value of the average class ExponentialMovingAverage { public: ExponentialMovingAverage(scalar_t alpha, scalar_t init): m_alpha(alpha), m_current_value(init) { } //! \brief Add a point in the series, return current average value scalar_t add_point(scalar_t value){ m_current_value = m_alpha*value + (1-m_alpha)*m_current_value; return m_current_value; } //! \brief Return the current average value scalar_t current_value() { return m_current_value; } //! \brief Reset the average to 'value' void reset(scalar_t value) { m_current_value = value; } //! \brief Set the parameter value void set_alpha(scalar_t alpha) {m_alpha = alpha;} private: scalar_t m_alpha; scalar_t m_current_value; }; } // end namespace utils } // end namespace specmicp #endif // SPECMICP_UTILS_MOVINGAVERAGE_HPP diff --git a/src/utils/options_handler.hpp b/src/utils/options_handler.hpp index 89e5ce7..9226793 100644 --- a/src/utils/options_handler.hpp +++ b/src/utils/options_handler.hpp @@ -1,76 +1,79 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_UTILS_OPTIONSHANDLER_HPP #define SPECMICP_UTILS_OPTIONSHANDLER_HPP namespace specmicp { //! \brief Class that handles the options template class OptionsHandler { public: //! \brief Initializa with the default options OptionsHandler() {} //! \brief Initialise the options class using the arguments provided template OptionsHandler(Args... args): m_options(args...) {} //! \brief Initialize with given options OptionsHandler(const OptionsClass& options): m_options(options) {} //! \brief Return a reference to the options OptionsClass& get_options() {return m_options;} //! \brief Return a const reference to the options const OptionsClass& get_options() const {return m_options;} //! \brief Set the options void set_options(const OptionsClass& options) {m_options = options;} //! \brief Swap the options with another set //! //! May be useful for temporary change void swap(OptionsClass& options) {std::swap(m_options, options);} //! \brief Reset to default options void reset_to_default() {m_options = OptionsClass();} private: OptionsClass m_options; //!< The options }; } // end namespace specmicp #endif // SPECMICP_UTILS_OPTIONSHANDLER_HPP diff --git a/src/utils/perfs_handler.hpp b/src/utils/perfs_handler.hpp index 0abb4f3..328dfd4 100644 --- a/src/utils/perfs_handler.hpp +++ b/src/utils/perfs_handler.hpp @@ -1,60 +1,63 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_UTILS_PERFSHANDLER_HPP #define SPECMICP_UTILS_PERFSHANDLER_HPP namespace specmicp { //! \brief Handle a performance struct for the algorithms //! //! Like options handler but for the performance template class PerformanceHandler { public: //! \brief Return the performance (read-only) const PerformanceStruct& get_perfs() const {return m_perfs;} //! \brief Reset the performance void reset_perfs() {m_perfs = PerformanceStruct();} //! \brief Return a reference to the performance PerformanceStruct& get_perfs() {return m_perfs;} protected: //! \brief Swap the performance with another void swap(PerformanceStruct& other) {std::swap(m_perfs, other);} private: PerformanceStruct m_perfs; }; } // end namespace specmicp #endif // SPECMICP_UTILS_PERFSHANDLER_HPP diff --git a/src/utils/sparse_solvers/sparse_bicgstab.hpp b/src/utils/sparse_solvers/sparse_bicgstab.hpp index 0e6689c..0fdee64 100644 --- a/src/utils/sparse_solvers/sparse_bicgstab.hpp +++ b/src/utils/sparse_solvers/sparse_bicgstab.hpp @@ -1,98 +1,101 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPARSESOLVERS_SPARSEBICGSTAB_HPP #define SPECMICP_SPARSESOLVERS_SPARSEBICGSTAB_HPP #include "sparse_solver_structs.hpp" #include "sparse_solver_base.hpp" #include namespace specmicp { namespace sparse_solvers { template class SparseSolverBiCGSTAB: public SparseSolverBase { using SolverT = Eigen::BiCGSTAB>; public: void analyse_pattern(MatrixT& jacobian) { m_solver.analyzePattern(jacobian); } //! \brief Decompose the jacboian SparseSolverReturnCode decompose(MatrixT& jacobian) { m_solver.compute(jacobian); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedDecomposition; } return SparseSolverReturnCode::Success; } //! \brief Solve the problem SparseSolverReturnCode solve( const DerivedR& residuals, DerivedS& solution ) { solution = m_solver.solve(-residuals); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedSystemSolving; } return SparseSolverReturnCode::Success; } SparseSolverReturnCode solve_scaling( const DerivedR& residuals, const DerivedR& scaling, DerivedS& solution ) { solution = m_solver.solve(scaling.asDiagonal()*(-residuals)); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedSystemSolving; } return SparseSolverReturnCode::Success; } private: SolverT m_solver; }; } // end namespace sparse_solvers } // end namespace specmicp #endif //SPECMICP_SPARSESOLVERS_SPARSEBICGSTAB_HPP diff --git a/src/utils/sparse_solvers/sparse_gmres.hpp b/src/utils/sparse_solvers/sparse_gmres.hpp index 41ed97c..61fd9d7 100644 --- a/src/utils/sparse_solvers/sparse_gmres.hpp +++ b/src/utils/sparse_solvers/sparse_gmres.hpp @@ -1,100 +1,103 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPARSESOLVERS_SPARSEGMRES_HPP #define SPECMICP_SPARSESOLVERS_SPARSEGMRES_HPP #include "sparse_solver_structs.hpp" #include "sparse_solver_base.hpp" // needed for eigen 3.2.2 #include #include namespace specmicp { namespace sparse_solvers { template class SparseSolverGMRES: public SparseSolverBase { using SolverT = Eigen::GMRES> ; public: void analyse_pattern(MatrixT& jacobian) { } //! \brief Decompose the jacboian SparseSolverReturnCode decompose(MatrixT& jacobian) { m_solver.compute(jacobian); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedDecomposition; } return SparseSolverReturnCode::Success; } //! \brief Solve the problem SparseSolverReturnCode solve( const DerivedR& residuals, DerivedS& solution ) { solution = m_solver.solve(-residuals); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedSystemSolving; } return SparseSolverReturnCode::Success; } SparseSolverReturnCode solve_scaling( const DerivedR& residuals, const DerivedR& scaling, DerivedS& solution ) { solution = m_solver.solve(scaling.asDiagonal()*(-residuals)); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedSystemSolving; } return SparseSolverReturnCode::Success; } private: SolverT m_solver; }; } // end namespace sparse_solvers } // end namespace specmicp #endif //SPECMICP_SPARSESOLVERS_SPARSEGMRES_HPP diff --git a/src/utils/sparse_solvers/sparse_lu.hpp b/src/utils/sparse_solvers/sparse_lu.hpp index b79dba4..16e5c8e 100644 --- a/src/utils/sparse_solvers/sparse_lu.hpp +++ b/src/utils/sparse_solvers/sparse_lu.hpp @@ -1,98 +1,101 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPARSESOLVERS_SPARSELU_HPP #define SPECMICP_SPARSESOLVERS_SPARSELU_HPP #include "sparse_solver_structs.hpp" #include "sparse_solver_base.hpp" #include namespace specmicp { namespace sparse_solvers { template class SparseSolverLU: public SparseSolverBase { using SolverT = Eigen::SparseLU>; public: void analyse_pattern(MatrixT& jacobian) { m_solver.analyzePattern(jacobian); } //! \brief Decompose the jacboian SparseSolverReturnCode decompose(MatrixT& jacobian) { m_solver.factorize(jacobian); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedDecomposition; } return SparseSolverReturnCode::Success; } //! \brief Solve the problem SparseSolverReturnCode solve( const DerivedR& residuals, DerivedS& solution ) { solution = m_solver.solve(-residuals); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedSystemSolving; } return SparseSolverReturnCode::Success; } SparseSolverReturnCode solve_scaling( const DerivedR& residuals, const DerivedR& scaling, DerivedS& solution ) { solution = m_solver.solve(scaling.asDiagonal()*(-residuals)); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedSystemSolving; } return SparseSolverReturnCode::Success; } private: SolverT m_solver; }; } // end namespace sparse_solvers } // end namespace specmicp #endif //SPECMICP_SPARSESOLVERS_SPARSELU_HPP diff --git a/src/utils/sparse_solvers/sparse_qr.hpp b/src/utils/sparse_solvers/sparse_qr.hpp index 822c5ee..7d59633 100644 --- a/src/utils/sparse_solvers/sparse_qr.hpp +++ b/src/utils/sparse_solvers/sparse_qr.hpp @@ -1,98 +1,101 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPARSESOLVERS_SPARSEQR_HPP #define SPECMICP_SPARSESOLVERS_SPARSEQR_HPP #include "sparse_solver_structs.hpp" #include "sparse_solver_base.hpp" #include namespace specmicp { namespace sparse_solvers { template class SparseSolverQR: public SparseSolverBase { using SolverT = Eigen::SparseQR>; public: void analyse_pattern(MatrixT& jacobian) { m_solver.analyzePattern(jacobian); } //! \brief Decompose the jacboian SparseSolverReturnCode decompose(MatrixT& jacobian) { m_solver.factorize(jacobian); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedDecomposition; } return SparseSolverReturnCode::Success; } //! \brief Solve the problem SparseSolverReturnCode solve( const DerivedR& residuals, DerivedS& solution ) { solution = m_solver.solve(-residuals); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedSystemSolving; } return SparseSolverReturnCode::Success; } SparseSolverReturnCode solve_scaling( const DerivedR& residuals, const DerivedR& scaling, DerivedS& solution ) { solution = m_solver.solve(scaling.asDiagonal()*(-residuals)); if (m_solver.info() != Eigen::Success) { return SparseSolverReturnCode::FailedSystemSolving; } return SparseSolverReturnCode::Success; } private: SolverT m_solver; }; } // end namespace sparse_solvers } // end namespace specmicp #endif //SPECMICP_SPARSESOLVERS_SPARSEQR_HPP diff --git a/src/utils/sparse_solvers/sparse_solver.hpp b/src/utils/sparse_solvers/sparse_solver.hpp index 95aa9f6..87d619c 100644 --- a/src/utils/sparse_solvers/sparse_solver.hpp +++ b/src/utils/sparse_solvers/sparse_solver.hpp @@ -1,78 +1,81 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPARSESOLVERS_SPARSESOLVERS_HPP #define SPECMICP_SPARSESOLVERS_SPARSESOLVERS_HPP #include #include "sparse_qr.hpp" #include "sparse_lu.hpp" #include "sparse_bicgstab.hpp" #ifdef EIGEN_UNSUPPORTED_FOUND #include "sparse_gmres.hpp" #endif namespace specmicp { namespace sparse_solvers { template using SparseSolverPtr = std::unique_ptr>; template SparseSolverPtr get_sparse_solver(SparseSolver solver_type) { SparseSolverPtr sparse_solver; switch (solver_type) { case SparseSolver::SparseQR: sparse_solver = SparseSolverPtr( new SparseSolverQR); break; #ifdef EIGEN_UNSUPPORTED_FOUND case SparseSolver::GMRES: sparse_solver = SparseSolverPtr( new SparseSolverGMRES); break; #endif case SparseSolver::SparseLU: sparse_solver = SparseSolverPtr( new SparseSolverLU); break; case SparseSolver::BiCGSTAB: sparse_solver = SparseSolverPtr( new SparseSolverBiCGSTAB); break; } return sparse_solver; } } // end namespace sparse_solvers } // end namespace specmicp #endif //SPECMICP_SPARSESOLVERS_SPARSESOLVERS_HPP diff --git a/src/utils/sparse_solvers/sparse_solver_base.hpp b/src/utils/sparse_solvers/sparse_solver_base.hpp index 059a335..f5bbcff 100644 --- a/src/utils/sparse_solvers/sparse_solver_base.hpp +++ b/src/utils/sparse_solvers/sparse_solver_base.hpp @@ -1,57 +1,60 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_SPARSESOLVERS_SPARSESOLVERSBASE_HPP #define SPECMICP_SPARSESOLVERS_SPARSESOLVERSBASE_HPP namespace specmicp { namespace sparse_solvers { enum class SparseSolverReturnCode; //! \brief Abstract Base Class for a sparse solver template class SparseSolverBase { public: virtual ~SparseSolverBase() {} virtual void analyse_pattern(MatrixT& jacobian) = 0; //! \brief Decompose the jacboian virtual SparseSolverReturnCode decompose(MatrixT& jacobian) = 0; //! \brief Solve the problem virtual SparseSolverReturnCode solve(const DerivedR& residuals, DerivedS& solution) = 0; //! \brief Solve the problem virtual SparseSolverReturnCode solve_scaling(const DerivedR& residuals, const DerivedR& scaling, DerivedS& solution) = 0; }; } // end namespace sparse_solvers } // end namespace specmicp #endif //SPECMICP_SPARSESOLVERS_SPARSESOLVERSBASE_HPP diff --git a/src/utils/sparse_solvers/sparse_solver_structs.hpp b/src/utils/sparse_solvers/sparse_solver_structs.hpp index 56b7090..fe9ccbe 100644 --- a/src/utils/sparse_solvers/sparse_solver_structs.hpp +++ b/src/utils/sparse_solvers/sparse_solver_structs.hpp @@ -1,63 +1,66 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_UTILS_SPARSESOLVERSTRUCT_HPP #define SPECMICP_UTILS_SPARSESOLVERSTRUCT_HPP namespace specmicp { namespace sparse_solvers { //! \brief Available sparse solver enum class SparseSolver { SparseLU, //!< Eigen Sparse LU solver SparseQR, //!< Eigen Sparse QR solver BiCGSTAB //!< Eigen BiCGSTAB solver #ifdef EIGEN_UNSUPPORTED_FOUND , GMRES //!< Eigen unsupported GMRES solver #endif }; enum class SparseSolverReturnCode { FailedDecomposition =-2, //!< Decomposition has failed FailedSystemSolving =-1, //!< Solving linear system has failed Success = 0 //!< Success }; } // end namespace sparse_solvers using SparseSolver = sparse_solvers::SparseSolver; } // end namespace specmicp #endif //SPECMICP_DFPMSOLVER_SPARSESOLVERSTRUCT_HPP diff --git a/src/utils/timer.hpp b/src/utils/timer.hpp index b9604fd..87ace3e 100644 --- a/src/utils/timer.hpp +++ b/src/utils/timer.hpp @@ -1,92 +1,95 @@ -/*------------------------------------------------------- +/*------------------------------------------------------------------------------- -Copyright (c) 2014,2015 Fabien Georget , Princeton University +Copyright (c) 2014,2015 F. 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: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the Princeton University nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +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 OWNER OR CONTRIBUTORS BE LIABLE FOR +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 +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. ----------------------------------------------------------*/ +-----------------------------------------------------------------------------*/ #ifndef SPECMICP_UTILS_TIMER_HPP #define SPECMICP_UTILS_TIMER_HPP #include #include namespace specmicp { //! \brief A simple timer class Timer { public: //! \brief Initialize the timer and start it Timer() { start(); } //! \brief Start the timer void start() { m_start = std::chrono::system_clock::now(); } //! \brief Stop the timer void stop() { m_end = std::chrono::system_clock::now(); } //! \brief Return the time of the starting point std::time_t get_start() const { return std::chrono::system_clock::to_time_t(m_start); } //! \brief Return the time of the ending point std::time_t get_stop() const { return std::chrono::system_clock::to_time_t(m_end); } //! \brief Return a textual representation (ctime) of the starting point char* get_ctime_start() const { std::time_t start_time = get_start(); return std::ctime(&start_time); } //! \brief Return a textual representation (ctime) of the ending point char* get_ctime_stop() const { std::time_t stop_time = get_stop(); return std::ctime(&stop_time); } //! \brief Return the elapsed time (in seconds) double elapsed_time() const { std::chrono::duration elapsed_seconds = m_end-m_start; return elapsed_seconds.count(); } private: std::chrono::time_point m_start; std::chrono::time_point m_end; }; } // end namespace specmicp #endif // SPECMICP_UTILS_TIMER_HPP