diff --git a/cython/specmicp/constraints.pxd b/cython/specmicp/constraints.pxd
index 4397632..5514558 100644
--- a/cython/specmicp/constraints.pxd
+++ b/cython/specmicp/constraints.pxd
@@ -1,76 +1,85 @@
 # Copyright (c) 2014,2015 Fabien Georget <fabieng@princeton.edu>, Princeton University
 # All rights reserved.
 
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are met:
 #    * 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
diff --git a/cython/specmicp/constraints.pyx b/cython/specmicp/constraints.pyx
index 3d95197..2bcd1ba 100644
--- a/cython/specmicp/constraints.pyx
+++ b/cython/specmicp/constraints.pyx
@@ -1,165 +1,164 @@
 # Copyright (c) 2014,2015 Fabien Georget <fabieng@princeton.edu>, Princeton University
 # All rights reserved.
 
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are met:
 #    * 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.
 
-
-
 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
diff --git a/cython/specmicp/database.pxd b/cython/specmicp/database.pxd
index 87e1b50..94300e3 100644
--- a/cython/specmicp/database.pxd
+++ b/cython/specmicp/database.pxd
@@ -1,98 +1,104 @@
 # Copyright (c) 2014,2015 Fabien Georget <fabieng@princeton.edu>, Princeton University
 # All rights reserved.
 
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are met:
 #    * 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.
 
 
 
 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);
+        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);
-        float nu_aqueous(int, int);
-        float logk_aqueous(int);
+        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);
-        float nu_mineral(int, int);
-        float logk_mineral(int);
-
-        int nb_mineral_kinetic();
+        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)
+
+        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)
 
 
 # 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(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()
         # 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)
 
 
 # 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 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 c24df58..a65a485 100644
--- a/cython/specmicp/database.pyx
+++ b/cython/specmicp/database.pyx
@@ -1,230 +1,310 @@
 # Copyright (c) 2014,2015 Fabien Georget <fabieng@princeton.edu>, Princeton University
 # All rights reserved.
 
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are met:
 #    * 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.
 
 
 
 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"""
         self.database = new Database(filepath)
         self.container = self.database.get_database()
     def __dealloc__(self):
         del self.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();
 
     # --------- #
     # 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 secondary aqueous species"""
+        """ 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_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_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 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 of 'mineral'"""
+        return self.molar_mass_mineral_kinetic(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_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 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 of 'mineral'"""
+        return self.molar_mass_mineral(self.mineral_label_to_id(mineral))
\ No newline at end of file
diff --git a/cython/specmicp/solution.pxd b/cython/specmicp/solution.pxd
index 241b6a6..3bc2fd5 100644
--- a/cython/specmicp/solution.pxd
+++ b/cython/specmicp/solution.pxd
@@ -1,87 +1,98 @@
 # Copyright (c) 2014,2015 Fabien Georget <fabieng@princeton.edu>, Princeton University
 # All rights reserved.
 
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are met:
 #    * 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.
 
 
 
 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
-        VectorXd main_variables
-
 
+# 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
             )
 
         float volume_fraction_water()
         float density_water()
         float saturation_water()
         float saturation_gas_phase()
         float porosity()
         float pE()
         float Eh()
         float molality_component(int)
         float activity_component(int)
         float volume_fraction_mineral(int)
         float mole_concentration_mineral(int)
         float mass_concentration_mineral(int)
         float saturation_index(int)
         float free_surface_concentration()
         float ionic_strength()
         float pH()
         float molality_aqueous(int)
         float activity_aqueous(int)
         float gas_fugacity(int)
         float sorbed_species_molalities(int)
         float total_aqueous_concentration(int)
         float total_solid_concentration(int)
         float total_immobile_concentration(int)
+        VectorXd get_main_variables()
+
+
 
+# Cython wrapper
+# --------------
+# the extractor only contains a reference to the solution
+# so we need to store the solution also
 cdef class SpecMiCPSolution:
-    """This class contains the solution from a specmicp computation."""
     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 8ac4541..ab1caf2 100644
--- a/cython/specmicp/solution.pyx
+++ b/cython/specmicp/solution.pyx
@@ -1,139 +1,151 @@
 # Copyright (c) 2014,2015 Fabien Georget <fabieng@princeton.edu>, Princeton University
 # All rights reserved.
 
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are met:
 #    * 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.
 
 
 
 from solution cimport SpecMiCPSolution
 from cython.operator cimport dereference
 from database cimport DataContainer
 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()
     # 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.gas_fugacity(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.sorbed_species_molalities(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)
diff --git a/cython/specmicp/solver.pxd b/cython/specmicp/solver.pxd
index 1998df4..a93fe75 100644
--- a/cython/specmicp/solver.pxd
+++ b/cython/specmicp/solver.pxd
@@ -1,39 +1,43 @@
 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),
+        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() # read-only
+        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)
-    cdef AdimensionalSystemOptions* get_system_options(self)
-    cdef MiCPSolverOptions* get_micpsolver_options(self)
+    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 4c320e0..381392e 100644
--- a/cython/specmicp/solver.pyx
+++ b/cython/specmicp/solver.pyx
@@ -1,209 +1,221 @@
 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)
+            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):
+    cdef AdimensionalSystemSolverOptions* get_options(self) nogil:
+        """Return the options"""
         return &(self.solver.get_options())
 
-    cdef AdimensionalSystemOptions* get_system_options(self):
+    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):
+    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 initialise_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()
-        perf = self.solver.solve(dereference(self.variables), initialize)
+        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_tolerance(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):
         """Set the maximum step length"""
         self.get_micpsolver_options().set_maximum_step_length(max_step_length)
     def set_maximum_step_length(self, max_step_length, max_iter_at_max_length):
         """Set the maximum step length"""
         self.get_micpsolver_options().set_maximum_step_length(
             max_step_length, max_iter_at_max_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 ed538eb..3599695 100644
--- a/cython/specmicp/solver_options.pxd
+++ b/cython/specmicp/solver_options.pxd
@@ -1,120 +1,120 @@
 # Copyright (c) 2014,2015 Fabien Georget <fabieng@princeton.edu>, Princeton University
 # All rights reserved.
 
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are met:
 #    * 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 libcpp cimport bool
 from units cimport UnitsSet
 
 cdef extern from "micpsolver/micpsolver_structs.hpp" namespace "specmicp::micpsolver":
     cdef cppclass MiCPSolverOptions:
         MiCPSolverOptions()
         int max_iter
-        float fvectol
-        float steptol
-        float condition_limit
-        float penalization_factor
-        float maxstep
+        double fvectol
+        double steptol
+        double condition_limit
+        double penalization_factor
+        double maxstep
         int maxiter_maxstep
-        float factor_descent_condition
-        float power_descent_condition
+        double factor_descent_condition
+        double power_descent_condition
         bool use_crashing
-        float coeff_accept_newton_step
+        double coeff_accept_newton_step
         bool use_scaling
-        float factor_gradient_search_direction
-        float projection_min_variable
-        float threshold_stationary_point
+        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(float)
-        void set_maximum_step_length(float, int)
+        void set_maximum_step_length(double)
+        void set_maximum_step_length(double, int)
         void disable_descent_direction()
-        void enable_descent_direction(float, float)
+        void enable_descent_direction(double, double)
         void disable_condition_check()
-        void enable_condition_check(float)
+        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(float)
-        void set_tolerance(float, float)
+        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
-        float scaling_electron
-        float non_ideality_tolerance
-        float under_relaxation_factor
-        float restart_concentration
-        float new_component_concentration
-        float start_non_ideality_computation
-        float cutoff_total_concentration
+        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 4f4d0d3..ee1006f 100644
--- a/cython/specmicp/units.pxd
+++ b/cython/specmicp/units.pxd
@@ -1,46 +1,47 @@
 # Copyright (c) 2014,2015 Fabien Georget <fabieng@princeton.edu>, Princeton University
 # All rights reserved.
 
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are met:
 #    * 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.
 
 
 
 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
diff --git a/tests/cython/database.py b/tests/cython/database.py
index 0f3ed16..90e8567 100644
--- a/tests/cython/database.py
+++ b/tests/cython/database.py
@@ -1,76 +1,76 @@
 #!/usr/bin/env python
 
 import unittest as ut
 import sys
 
 lib_directory = "@python_module_path@"
 database_path = b"@database_path@"
 
 sys.path.insert(0, lib_directory)
 
 import specmicp.database as database
 
 
 class TestDatabase(ut.TestCase):
 
     def test_init(self):
         db = database.DatabaseManager(database_path)
         self.assertTrue(db.is_valid())
         self.assertTrue(db.nb_component > 0)
         self.assertTrue(db.nb_aqueous > 0)
         self.assertTrue(db.nb_mineral > 0)
 
     def test_access_aqueous(self):
         db = database.DatabaseManager(database_path)
         self.assertTrue(db.nb_aqueous > 0)
         self.assertTrue(db.nb_aqueous > 2)
         self.assertTrue(db.nb_component > 3)
         label = db.aqueous_id_to_label(2)
         self.assertEqual(db.aqueous_label_to_id(label), 2)
         self.assertIsNotNone(db.nu_aqueous(2, 2))
         self.assertEqual(db.l_nu_aqueous(label, db.component_id_to_label(2)),
                          db.nu_aqueous(2, 2))
         self.assertIsNotNone(db.nu_aqueous(2, 3))
         self.assertEqual(db.l_nu_aqueous(label, db.component_id_to_label(3)),
                          db.nu_aqueous(2, 3))
 
     def test_access_mineral(self):
         db = database.DatabaseManager(database_path)
         self.assertTrue(db.nb_mineral > 0)
         self.assertTrue(db.nb_mineral > 2)
         self.assertTrue(db.nb_component > 3)
         label = db.mineral_id_to_label(2)
         self.assertEqual(db.mineral_label_to_id(label), 2)
         self.assertIsNotNone(db.nu_mineral(2, 2))
         self.assertEqual(db.l_nu_mineral(label, db.component_id_to_label(2)),
                          db.nu_mineral(2, 2))
         self.assertIsNotNone(db.nu_mineral(2, 3))
         self.assertEqual(db.l_nu_mineral(label, db.component_id_to_label(3)),
                          db.nu_mineral(2, 3))
 
     def test_switch_basis(self):
         db = database.DatabaseManager(database_path)
         swapping = {b"H[+]": b"HO[-]",
                     b"Al[3+]": b"Al(OH)4[-]"
                    }
         db.swap_components(swapping)
         for (key, value) in swapping.items():
             self.assertRaises(ValueError, db.component_label_to_id, key)
             self.assertNotEqual(db.aqueous_label_to_id(key), -1)
             self.assertNotEqual(db.component_label_to_id(value), -1)
             self.assertRaises(ValueError, db.aqueous_label_to_id, value)
 
     def mineral_keep_only(self):
         db = database.DatabaseManager(database_path)
         mineral_to_keep = (b"Portlandite", b"Gypsum", b"Straetlingite")
         logks = [db.l_logk_mineral(mineral) for mineral in mineral_to_keep]
         db.minerals_keep_only(mineral_to_keep)
         db.assertEqual(db.nb_mineral, 3)
         for i in range(db.nb_mineral):
-            assertTrue(db.mineral_id_to_label(i) in mineral_to_keep)
-            assertTrue(db.logk_mineral(i) in logks)
+            self.assertTrue(db.mineral_id_to_label(i) in mineral_to_keep)
+            self.assertTrue(db.logk_mineral(i) in logks)
 
 
 if __name__ == '__main__':
     ut.main()
 
diff --git a/tests/cython/test_specmicp.py b/tests/cython/test_specmicp.py
index 8dd2e58..e4570cb 100644
--- a/tests/cython/test_specmicp.py
+++ b/tests/cython/test_specmicp.py
@@ -1,53 +1,52 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
 import unittest as ut
 import sys
 
 lib_directory = "@python_module_path@"
 database_path = b"@database_path@"
 
 sys.path.insert(0, lib_directory)
 
 import specmicp.database as database
-import specmicp.solution as solution
 import specmicp.constraints as constraints
 import specmicp.solver as solver
 
 
 class TestSpecmicp(ut.TestCase):
 
     def setUp(self):
         self.db = database.DatabaseManager(database_path)
         swapping = {b"H[+]": b"HO[-]",
             }
         self.db.swap_components(swapping)
 
     def test_solver(self):
         formulation = constraints.SpecMiCPFormulation(self.db)
         formulation.set_mass_solution(0.5)
         formulation.add_mineral(b"Portlandite", 10)
         formulation.add_aqueous_species(b"CO2", 0.5)
         formulation.initialize_system()
 
         the_solver = solver.SpecMiCPSolver(self.db, formulation, None)
         the_solver.set_length_unit("decimeter")
         the_solver.solve()
 
         the_solution = the_solver.get_solution()
         self.assertTrue(abs(the_solution.pH() - 12.487998) < 1e-3)
 
-    def test_solver(self):
+    def test_solver_fail(self):
         formulation = constraints.SpecMiCPFormulation(self.db)
         formulation.set_mass_solution(0.5)
         formulation.add_mineral(b"Portlandite", 10000)
         formulation.add_aqueous_species(b"CO2", 0.5)
         formulation.initialize_system()
 
         the_solver = solver.SpecMiCPSolver(self.db, formulation, None)
         the_solver.set_length_unit("decimeter")
         self.assertRaises(RuntimeError, the_solver.solve)
 
 
 if __name__ == '__main__':
     ut.main()