# Path: DiscEvolution/constants.py
# G = 1.
# AU = 1.496e13
# 
# Path: DiscEvolution/chemistry/base_chem.py
# class ChemicalAbund(object):
#     """Simple wrapper class to hold chemical species data.
# 
#     Holds the mass abundance (g) of the chemical species relative to Hydrogen.
# 
#     args:
#         species : list, maps species name to location in data array
#         masses  : array, molecular masses in atomic mass units
#         size    : Number of data points to hold chemistry for
#     """
#     def __init__(self, species, masses,*sizes):
#         # Sizes is dimension zero if not specified
#         sizes = sizes if sizes else (0,)
#         if len(masses) != len(species):
#             raise AttributeError("Number of masses must match the number of"
#                                  "species")
# 
#         self._indexes = dict([(name, i) for i, name in enumerate(species)])
#         self._names   = species
#         self._mass    = masses
#         self._Nspec = len(self._names)
# 
#         self._data = np.zeros((self.Nspec,) + sizes, dtype='f8')
# 
#     def __getitem__(self, k):
#         return self._data[self._indexes[k]]
# 
#     def __setitem__(self, k, val):
#         self._data[self._indexes[k]] = val
# 
#     def __iadd__(self, other):
#         if self.names != other.names:
#             raise AttributeError("Chemical species must be the same")
# 
#         self._data += other._data    
#         return self
# 
#     def __iter__(self):
#         return iter(self._names)
# 
#     def copy(self):
#         return copy.deepcopy(self)
#             
#     def number_abund(self, k):
#         """Number abundance of species k, n_k= rho_k / m_k"""
#         return self[k]/self.mass(k)
# 
#     @property
#     def total_abund(self):
#         return self._data.sum(0)
#     
#     def set_number_abund(self, k, n_k):
#         """Set the mass abundance from the number abundance"""
#         self[k] = n_k * self.mass(k)
# 
#     def to_array(self):
#         """Get the raw data"""
#         return self.data
# 
#     def from_array(self, data):
#         """Set the raw data"""
#         if data.shape[0] == self.Nspec:
#             raise AttributeError("Error: shape must be [Nspec, *]")
#         self._data = data
# 
#    #def resize(self, n):
#     #    '''Resize the data array, keeping any elements that we already have'''
#     #    dn = n - self.size
#     #    if dn < 0:
#     #        self._data = self._data[:,:n].copy()
#     #    else:
#     #        self._data = np.concatenate([self._data,
#     #                                     np.empty([self.Nspec,dn],dtype='f8')])
#     def resize(self, shape):
#         '''Resize the data array, keeping any elements that we already have'''
#         try:
#             shape = (self.Nspec, ) + tuple(shape)
#         except TypeError:
#             if type(shape) != type(1):
#                 raise TypeError("shape must be int, or array of int")
#             shape = (self.Nspec, shape)
# 
#         new_data = np.zeros(shape, dtype='f8')
#         
#         idx = [ slice(0, min(ni)) for ni in zip(shape, self._data.shape)]
# 
#         # Copy accross the old data
#         new_data[idx] = self._data[idx]
# 
#         self._data = new_data
# 
#     def append(self, other):
#         """Append chemistry data from another container"""
#         if self.names != other.names:
#             raise  AttributeError("Chemical species must be the same")
# 
#         self._data = np.append(self._data, other.data)
#             
#     def mass(self, k):
#         """Mass of species in atomic mass units"""
#         return self._mass[self._indexes[k]]
# 
#     def mu(self):
#         '''Mean molecular weight'''
#         return self._data.sum(0) / (self._data.T / self._mass).sum(1)
# 
#     @property
#     def masses(self):
#         """Masses of all species in amu"""
#         return self._mass
# 
#     @property
#     def names(self):
#         """Names of the species in order"""
#         return self._names
# 
#     @property
#     def Nspec(self):
#         return self._Nspec
# 
#     @property
#     def species(self):
#         """Names of the chemical species held."""
#         return self._indexes.keys()
# 
#     @property
#     def data(self):
#         return self._data
# 
#     @property
#     def size(self):
#         return self._data.shape[1]


from collections import defaultdict
from ..constants import m_H, m_n, m_e
from .base_chem import ChemicalAbund
import re
import numpy as np


__all__ = [ "atomic_mass", "molecular_mass", "atomic_composition",
            "atomic_abundances" ]

ATOMIC_MASSES = {
    'H'  :    m_H,          'He' :  2*(m_H + m_n),
    
    'C'  :  6*(m_H + m_n),  'N'  :  7*(m_H + m_n),  'O'  :  8*(m_H + m_n),
    'Ne' : 10*(m_H + m_n),

    'Na' : 11*m_H + 12*m_n, 'Mg' : 12*(m_H + m_n),  'Al' : 13*m_H + 14*m_n,
    'Si' : 14*(m_H + m_n),  'P'  : 15*m_H + 16*m_n, 'S'  : 16*(m_H + m_n),

# Path: DiscEvolution/constants.py
# G = 1.
# AU = 1.496e13
# 
# Path: DiscEvolution/chemistry/base_chem.py
# class ChemicalAbund(object):
#     """Simple wrapper class to hold chemical species data.
# 
#     Holds the mass abundance (g) of the chemical species relative to Hydrogen.
# 
#     args:
#         species : list, maps species name to location in data array
#         masses  : array, molecular masses in atomic mass units
#         size    : Number of data points to hold chemistry for
#     """
#     def __init__(self, species, masses,*sizes):
#         # Sizes is dimension zero if not specified
#         sizes = sizes if sizes else (0,)
#         if len(masses) != len(species):
#             raise AttributeError("Number of masses must match the number of"
#                                  "species")
# 
#         self._indexes = dict([(name, i) for i, name in enumerate(species)])
#         self._names   = species
#         self._mass    = masses
#         self._Nspec = len(self._names)
# 
#         self._data = np.zeros((self.Nspec,) + sizes, dtype='f8')
# 
#     def __getitem__(self, k):
#         return self._data[self._indexes[k]]
# 
#     def __setitem__(self, k, val):
#         self._data[self._indexes[k]] = val
# 
#     def __iadd__(self, other):
#         if self.names != other.names:
#             raise AttributeError("Chemical species must be the same")
# 
#         self._data += other._data    
#         return self
# 
#     def __iter__(self):
#         return iter(self._names)
# 
#     def copy(self):
#         return copy.deepcopy(self)
#             
#     def number_abund(self, k):
#         """Number abundance of species k, n_k= rho_k / m_k"""
#         return self[k]/self.mass(k)
# 
#     @property
#     def total_abund(self):
#         return self._data.sum(0)
#     
#     def set_number_abund(self, k, n_k):
#         """Set the mass abundance from the number abundance"""
#         self[k] = n_k * self.mass(k)
# 
#     def to_array(self):
#         """Get the raw data"""
#         return self.data
# 
#     def from_array(self, data):
#         """Set the raw data"""
#         if data.shape[0] == self.Nspec:
#             raise AttributeError("Error: shape must be [Nspec, *]")
#         self._data = data
# 
#    #def resize(self, n):
#     #    '''Resize the data array, keeping any elements that we already have'''
#     #    dn = n - self.size
#     #    if dn < 0:
#     #        self._data = self._data[:,:n].copy()
#     #    else:
#     #        self._data = np.concatenate([self._data,
#     #                                     np.empty([self.Nspec,dn],dtype='f8')])
#     def resize(self, shape):
#         '''Resize the data array, keeping any elements that we already have'''
#         try:
#             shape = (self.Nspec, ) + tuple(shape)
#         except TypeError:
#             if type(shape) != type(1):
#                 raise TypeError("shape must be int, or array of int")
#             shape = (self.Nspec, shape)
# 
#         new_data = np.zeros(shape, dtype='f8')
#         
#         idx = [ slice(0, min(ni)) for ni in zip(shape, self._data.shape)]
# 
#         # Copy accross the old data
#         new_data[idx] = self._data[idx]
# 
#         self._data = new_data
# 
#     def append(self, other):
#         """Append chemistry data from another container"""
#         if self.names != other.names:
#             raise  AttributeError("Chemical species must be the same")
# 
#         self._data = np.append(self._data, other.data)
#             
#     def mass(self, k):
#         """Mass of species in atomic mass units"""
#         return self._mass[self._indexes[k]]
# 
#     def mu(self):
#         '''Mean molecular weight'''
#         return self._data.sum(0) / (self._data.T / self._mass).sum(1)
# 
#     @property
#     def masses(self):
#         """Masses of all species in amu"""
#         return self._mass
# 
#     @property
#     def names(self):
#         """Names of the species in order"""
#         return self._names
# 
#     @property
#     def Nspec(self):
#         return self._Nspec
# 
#     @property
#     def species(self):
#         """Names of the chemical species held."""
#         return self._indexes.keys()
# 
#     @property
#     def data(self):
#         return self._data
# 
#     @property
#     def size(self):
#         return self._data.shape[1]


# Path: DiscEvolution/chemistry/atomic_data.py
from collections import defaultdict
from ..constants import m_H, m_n, m_e
from .base_chem import ChemicalAbund
import re
import numpy as np



__all__ = [ "atomic_mass", "molecular_mass", "atomic_composition",
            "atomic_abundances" ]

ATOMIC_MASSES = {
    'H'  :    m_H,          'He' :  2*(m_H + m_n),
    
    'C'  :  6*(m_H + m_n),  'N'  :  7*(m_H + m_n),  'O'  :  8*(m_H + m_n),
    'Ne' : 10*(m_H + m_n),

    'Na' : 11*m_H + 12*m_n, 'Mg' : 12*(m_H + m_n),  'Al' : 13*m_H + 14*m_n,
    'Si' : 14*(m_H + m_n),  'P'  : 15*m_H + 16*m_n, 'S'  : 16*(m_H + m_n),

    'Cl' : 17*m_H + 18*m_n, 'Ar' : 18*(m_H + m_n),