Page MenuHomec4science

database.pyx
No OneTemporary

File Metadata

Created
Mon, Jun 10, 06:25

database.pyx

# 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 #
# ------------ #
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"""
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))

Event Timeline