Source code for specie

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of the Cortix toolkit environment
# https://cortix.org
#
# All rights reserved, see COPYRIGHT for full restrictions.
# https://github.com/dpploy/cortix/blob/master/COPYRIGHT.txt
#
# Licensed under the University of Massachusetts Lowell LICENSE:
# https://github.com/dpploy/cortix/blob/master/LICENSE.txt
'''
Author: Valmor de Almeida dealmeidav@ornl.gov; vfda

This Specie class is to be used with other classes in plant-level process modules.

NB: Species is always used either in singular or plural cases, the class
    named here reflects one species. If many species are used in an external
    context, the species object name can be used without conflict.

For unit testing do at the linux command prompt:
    python specie.py

NB: The Specie() class encapsulates either the molecular or empirical chemical
    formula of a compound.
    This is done as follows. Say MAO2 is either a molecular or empirical chemical
    formula of a ficticious compound denoting minor actinides dioxide. The list
    of atoms is given as follows:

    ['0.49*Np-237', '0.42*Am-241', '0.08*Am-243', '0.01*Cm-244', '2.0*O-16']

    note the MA forming nuclides add to 1 = 0.49 + 0.42 + 0.08 + 0.01. Therefore
    the number of atoms in this compound is 3. 1 MA "atom" and 2 O.
    Note that the total number of "atoms" is obtained by summing all multipliers:
    0.49 + 0.42 + 0.08 + 0.01 + 2.0.
    The nuclide is indicated by the element symbol followed by a dash and the
    atomic mass number. Here the number of nuclide types is 5 (self._nNuclideTypes).

    The numbers preceeding the nuclide symbol before the * will be referred to as
    multipliers. The sum of the multipliers will add to the number of "atoms" in
    the formula. WARNING: a multiplier could be in the format 0.00e-00. In this
    case a hiphen may appear twice, e.g.: 1.549e-09*U-233

    Other forms can be used for common true species

    ['Np-237', '2.0*O-16'] or ['Np-237', 'O-16', 'O-16'] or [ '2*H', 'O' ] or
    [ 'H', 'O', 'H' ]  etc...

    This code will calculate the molar mass of any species with a given valid
    atom list using a provided periodic table of chemical elements. The user
    can also reset the value of the molar mass with a setter method.

Sat May  9 21:40:48 EDT 2015 created; vfda
'''
#*********************************************************************************
import os
import sys

from cortix.support.periodictable import ELEMENTS
#*********************************************************************************

[docs]class Specie: ''' todo: phase should not be here; concentrations should not be here only molar quantities should be here see the Phase container ''' #********************************************************************************* # Construction #********************************************************************************* def __init__(self, name='null', formula_name='null', phase='null', atoms=list(), molarCC=0.0, # default unit: M (mole/L) massCC=0.0, # default unit: g/L flag=None): assert isinstance(name, str), 'oops not string.' self._name = name assert isinstance(formula_name, str), 'oops not string.' self.__formula_name = formula_name assert isinstance(phase, str), 'oops not string.' self._phase = phase assert isinstance(atoms, list), 'oops not list.' self._atoms = atoms self._flag = flag # flag can be any type self._molarMass = 0.0 self._molarHeatPwr = 0.0 self._molarGammaPwr = 0.0 self._molarRadioactivity = 0.0 self._molarMassUnit = 'g/mole' self._molarHeatPwrUnit = 'W/mole' self._molarGammaPwrUnit = 'W/mole' self._molarRadioactivityUnit = 'Ci/mole' self._molarRadioactivityFractions = list() self._molarCCUnit = 'mole/L' self._massCCUnit = 'g/L' self.__UpdateMolarMass() if self._molarMass == 0.0: self._molarCC = 0.0 self._massCC = 0.0 return assert isinstance(molarCC, float), 'oops not a float.' assert molarCC >= 0.0, 'oops negative value.' self._molarCC = molarCC self._massCC = molarCC * self._molarMass assert isinstance(massCC, float), 'oops not a float.' assert massCC >= 0.0, 'oops negative value.' if self._massCC == 0.0: self._massCC = massCC self._molarCC = massCC / self._molarMass return #********************************************************************************* # Public Member Functions #*********************************************************************************
[docs] def GetName(self): ''' Returns the empirical name of the species. For example, "water". Returns ------- name: str ''' return self._name
[docs] def SetName(self, n): ''' Sets the empirical name of the species to n. Parameters ---------- n: str ''' self._name = n
name = property(GetName, SetName, None, None)
[docs] def GetFormulaName(self): ''' Returns the formulaic name of the compound. For example, "Dihydrogen monoxide". Returns ------- self.__formula_name: str ''' return self.__formula_name
[docs] def SetFormulaName(self, f): ''' Sets the formulaic name to f. Returns ------- self.__formula_name: str ''' self.__formula_name = f
formula_name = property(GetFormulaName, SetFormulaName, None, None)
[docs] def GetPhase(self): ''' Returns the phase history of the species. Returns ------- phase: dataFrame ''' return self._phase
[docs] def SetPhase(self, p): ''' Sets the phase history to p. Parameters ---------- p: dataFrame ''' self._mass = p
phase = property(GetPhase, SetPhase, None, None)
[docs] def GetMolarMass(self): ''' Returns the numerical value for the molar mass of the species. Units are given by molarMassUnit. Returns ------- molarMass: float ''' return self._molarMass
[docs] def SetMolarMass(self, v): ''' Sets the molar mass of the species equal to v. Parameters ---------- v: float ''' self._molarMass = v
molarMass = property(GetMolarMass, SetMolarMass, None, None)
[docs] def GetMolarMassUnit(self): ''' Returns the unit used to measure the molar mass of the species. Returns ------- molarMassUnit: str ''' return self._molarMassUnit
[docs] def SetMolarMassUnit(self, v): ''' Sets the unit used to measure the molar mass of the species to v. Parameters ---------- v: str ''' self._molarMassUnit = v
molarMassUnit = property(GetMolarMassUnit, SetMolarMassUnit, None, None)
[docs] def GetMolarRadioactivity(self): ''' Returns the numerical value for molar radioactivity of the species. Returns ------- molarRadioactivity: float ''' return self._molarRadioactivity
[docs] def SetMolarRadioactivity(self, v): ''' Sets the molar radioactivity of the species equal to v. Parameters ---------- v: float ''' self._molarRadioactivity = v
molarRadioactivity = property( GetMolarRadioactivity, SetMolarRadioactivity, None, None)
[docs] def GetMolarRadioactivityFractions(self): ''' Returns a list of numbers that speciefies the % of molar reactivity that comes from each type of atom in the species. For example, a molarRadioactivityFraction of [0.65, 0.35] for water means that 65% of the molar radioactivity comes from the hydrogen atoms and 35% comes from the oxygen atom. Returns ------- molarRadioactivityFractions: list ''' return self._molarRadioactivityFractions
[docs] def SetMolarRadioactivityFractions(self, fracs): ''' Sets molarRadioactivityFractions equal to fracs. Fracs must be a list of floatswith the same length as there are different atoms in the species, or the function call will fail. (e.g. self._atoms and fracs must be of the same length). Take care to ensure that the elements of fracs match with the elements of self._atoms! (65% is in the same position in fracs as hydrogen is in self._atoms, following the above example). Parameters ---------- fracs: list ''' assert isinstance(fracs, list), 'oops not list.' if len(fracs) > 0: assert len(fracs) == len(self._atoms), 'oops not right length,' if len(fracs) != 0: assert isinstance(fracs[-1], float), 'oops not float.' self._molarRadioactivityFractions = fracs
molarRadioactivityFractions = property( GetMolarRadioactivityFractions, SetMolarRadioactivityFractions, None, None)
[docs] def GetMolarRadioactivityUnit(self): ''' Returns the unit used to measure molar radioactivity. Returns ------- molarRadioactivityUnit: str ''' return self._molarRadioactivityUnit
[docs] def SetMolarRadioactivityUnit(self, v): ''' Sets the unit used to measure molar radioactivity to v. Parameters ---------- v: str ''' self._molarRadioactivityUnit = v
molarRadioactivityUnit = property( GetMolarRadioactivityUnit, SetMolarRadioactivityUnit, None, None)
[docs] def GetMolarHeatPwr(self): ''' Returns the amount of heat generated per mole of this species. Returns ------- molarHeatPwr: float ''' return self._molarHeatPwr
[docs] def SetMolarHeatPwr(self, v): ''' Sets the amount of heat generated per mole of this species to v. Parameters ---------- v: float ''' self._molarHeatPwr = v
molarHeatPwr = property(GetMolarHeatPwr, SetMolarHeatPwr, None, None)
[docs] def GetMolarHeatPwrUnit(self): ''' Returns the unit used to measure the amount of heat generated per mole of this species. Returns ------- molarHeatPwrUnit: str ''' return self._molarHeatPwrUnit
[docs] def SetMolarHeatPwrUnit(self, v): ''' Sets the unit used to measure the amount of heat generated per mole of this species to v. Parameters ---------- v: str ''' self._molarHeatPwrUnit = v
molarHeatPwrUnit = property( GetMolarHeatPwrUnit, SetMolarHeatPwrUnit, None, None)
[docs] def GetMolarGammaPwr(self): ''' Returns the amount of gamma radiation produced per mole of this species (measured in units of power). Returns ------- molarGammaPwr: float ''' return self._molarGammaPwr
[docs] def SetMolarGammaPwr(self, v): ''' Sets the amount of gamma radiation produced per mole of this species to v. Parameters ---------- v: float ''' self._molarGammaPwr = v
molarGammaPwr = property(GetMolarGammaPwr, SetMolarGammaPwr, None, None)
[docs] def GetMolarGammaPwrUnit(self): ''' Returns the unit used to measure the amount of gamma radiation produced per mole of this species. Returns ------- molarGammaPwrUnit: str ''' return self._molarGammaPwrUnit
[docs] def SetMolarGammaPwrUnit(self, v): ''' Sets the unit used to measure the amount of gamma radiation produced per mole of this species to v. Parameters ---------- v: str ''' self._molarGammaPwrUnit = v
molarGammaPwrUnit = property( GetMolarGammaPwrUnit, SetMolarGammaPwrUnit, None, None) # Deprecated; see new interface below as GetFormula
[docs] def GetAtoms(self): return self._atoms
[docs] def SetAtoms(self, atoms): assert isinstance(atoms, list), 'oops not list.' if len(atoms) != 0: assert isinstance(atoms[-1], str), 'oops not string.' self._atoms = atoms self.__UpdateMolarMass()
atoms = property(GetAtoms, SetAtoms, None, None) # New interface
[docs] def GetFormula(self): ''' Returns the molecular or empirical formula of the species. It is usually a list, for example, of the form ['2*H', 'O']. Returns ------- formula: list ''' return self._atoms
[docs] def SetFormula(self, atoms): ''' Sets the species' formula equal to atoms. Will automatically update the molar mass of the species, and will also fail if atoms is not a list of strings. Parameters ---------- atoms: list ''' assert isinstance(atoms, list), 'oops not list.' if len(atoms) != 0: assert isinstance(atoms[-1], str), 'oops not string.' self._atoms = atoms self.__UpdateMolarMass()
formula = property(GetFormula, SetFormula, None, None)
[docs] def GetNAtoms(self): # number of ficticious atoms in the species (see NB above) ''' Returns the total number of atoms comprising the species. For example, water is comprised of three atoms. Returns ------- nAtoms: int ''' return self._nAtoms
nAtoms = property(GetNAtoms, None, None, None) # number of nuclide types involved in the species definition
[docs] def GetNNuclideTypes(self): ''' Returns the number of different types of atoms comprising the species. For example, water is composed of two different types of atoms, hydrogen and oxygen. Returns ------- nNuclideTypes: int ''' return self._nNuclideTypes
nNuclideTypes = property(GetNNuclideTypes, None, None, None)
[docs] def SetFlag(self, f): ''' Sets the flag associated with the species to f. Parameters ---------- f: str ''' self._flag = f
[docs] def GetFlag(self): ''' Returns the flag associated with the species. Returns ------- flag: str ''' return self._flag
flag = property(GetFlag, SetFlag, None, None)
[docs] def GetMolarCC(self): ''' Returns the numerical value for the number (molar) density of the species (moles/volume). Returns ------- molarCC: float ''' return self._molarCC
[docs] def SetMolarCC(self, v): ''' Sets the numerical value for the molar density of the species to v. Parameters ---------- v: float ''' self._molarCC = v self._massCC = v * self._molarMass
molarCC = property(GetMolarCC, SetMolarCC, None, None)
[docs] def GetMolarCCUnit(self): ''' Returns the unit used to measure molar density of the species. Returns ------- molarCCUnit: str ''' return self._molarCCUnit
[docs] def SetMolarCCUnit(self, v): ''' Sets the unit used to measure the molar density of the species to v. Parameters ---------- v: str ''' self._molarCCUnit = v
molarCCUnit = property(GetMolarCCUnit, SetMolarCCUnit, None, None)
[docs] def GetMassCC(self): ''' Returns the numerical value of the mass density of the species (mass/volume). Returns ------- massCC: float ''' return self._massCC
[docs] def SetMassCC(self, v): ''' Sets the numerical value of the mass density equal to v. Parameters ---------- v: float ''' self._massCC = v if self._molarMass == 0.0 and v == 0.0: self._molarCC = 0.0 else: self._molarCC = v / self._molarMass
massCC = property(GetMassCC, SetMassCC, None, None)
[docs] def GetMassCCUnit(self): ''' Returns the unit used to measure the mass density of the species. Returns ------- massCCUnit: str ''' return self._massCCUnit
[docs] def SetMassCCUnit(self, v): ''' Sets the units used to measure mass density to v. Parameters ---------- v: str ''' self._massCCUnit = v
massCCUnit = property(GetMassCCUnit, SetMassCCUnit, None, None) def __str__(self): s = '\n\t Specie(): name=%s;' + ' formula_name=%s;' + ' phase=%s;' + '\n\t formula=%s;' + '\n\t # atoms=%s;' + ' # nuclide types=%s;' + ' molar mass=%9.3e[%s];' + ' molar cc=%9.3e[%s];' + ' mass cc=%9.3e[%s];' + '\n\t flag=%s;' + '\n\t molar radioactivity=%9.3e[%s];' + \ '\n\t radioactivity dens.=%9.3e[%s];' + '\n\t molar heat pwr=%9.3e[%s];' + '\n\t heat pwr dens.=%9.3e[%s];' + \ '\n\t molar gamma pwr=%9.3e[%s];' + '\n\t gamma pwr dens.=%9.3e[%s];' + \ '\n\t atoms=%s;' + '\n\t molar radioactivity fractions=%s' return s % (self.name, self.__formula_name, self.phase, self.__ReorderFormula(), self.nAtoms, self.nNuclideTypes, self.molarMass, self.molarMassUnit, self.molarCC, self.molarCCUnit, self.massCC, self.massCCUnit, self.flag, self.molarRadioactivity, self.molarRadioactivityUnit, self.molarRadioactivity * self.molarCC, '[Ci/cc]', self.molarHeatPwr, self.molarHeatPwrUnit, self.molarHeatPwr * self.molarCC, '[W/cc]', self.molarGammaPwr, self.molarGammaPwrUnit, self.molarGammaPwr * self.molarCC, '[W/cc]', [i.split('*')[-1] for i in self.formula], ['%9.3e' % i for i in self.molarRadioactivityFractions]) def __repr__(self): s = '\n\t Specie(): name=%s;' + ' formula_name=%s;' + ' phase=%s;' + '\n\t formula=%s;' + '\n\t # atoms=%s;' + ' # nuclide types=%s;' + ' molar mass=%9.3e[%s];' + ' molar cc=%9.3e[%s];' + ' mass cc=%9.3e[%s];' + '\n\t flag=%s;' + '\n\t molar radioactivity=%9.3e[%s];' + \ '\n\t radioactivity dens.=%9.3e[%s];' + '\n\t molar heat pwr=%9.3e[%s];' + '\n\t heat pwr dens.=%9.3e[%s];' + \ '\n\t molar gamma pwr=%9.3e[%s];' + '\n\t gamma pwr dens.=%9.3e[%s];' + \ '\n\t atoms=%s;' + '\n\t molar radioactivity fractions=%s' return s % (self.name, self.__formula_name, self.phase, self.__ReorderFormula(), self.nAtoms, self.nNuclideTypes, self.molarMass, self.molarMassUnit, self.molarCC, self.molarCCUnit, self.massCC, self.massCCUnit, self.flag, self.molarRadioactivity, self.molarRadioactivityUnit, self.molarRadioactivity * self.molarCC, '[Ci/cc]', self.molarHeatPwr, self.molarHeatPwrUnit, self.molarHeatPwr * self.molarCC, '[W/cc]', self.molarGammaPwr, self.molarGammaPwrUnit, self.molarGammaPwr * self.molarCC, '[W/cc]', [i.split('*')[-1] for i in self.formula], ['%9.3e' % i for i in self.molarRadioactivityFractions]) #********************************************************************************* # Private Helper Functions (Internal use: __) #********************************************************************************* def __UpdateMolarMass(self): ''' Updates the molar mass of the species after the molecular formula has been changed. ''' #if len(self._atoms) == 0: # self._nAtoms = 0 # return for entry in self._atoms: assert isinstance(entry, str), 'oops' tmp = entry.split('*') nuclide = tmp[-1] element = nuclide.split('-')[0] assert element in ELEMENTS, 'element = %r' % (element) self._nAtoms = 0 self._nNuclideTypes = 0 nuclides = dict() nAtoms = 0 summ = 0.0 for entry in self._atoms: assert isinstance(entry, str), 'oops' # format example: 3.2*O-18, or 3*O or O or O-16 tmp = entry.split('*') multiple = 1.0 # single nuclide if len(tmp) == 1: nuclide = tmp[0] # multiple nuclide elif len(tmp) == 2: multiple = float(tmp[0]) nuclide = tmp[1] else: assert False nuclides[nuclide] = multiple nAtoms += multiple try: tmp = nuclide.split('-') if len(tmp) == 1: element = ELEMENTS[tmp[0]] molarMass = element.exactmass # from isotopic composition if molarMass == 0.0: molarMass = element.mass elif len(tmp) == 2: element = ELEMENTS[tmp[0]].isotopes[int(tmp[1].strip('m'))] molarMass = element.mass else: assert False except KeyError: summ += multiple * 0.0 else: summ += multiple * molarMass self._molarMass = summ # print( summ ) self._nAtoms = nAtoms self._nNuclideTypes = len(nuclides) return def __ReorderFormula(self): ''' Takes a list of atoms for a molecular or empirical formula and places it in order of decreasing magnitude of stoichiometric coefficient. For example, [O, 2*H] will be returned as [2*H, O]. Returns ------- atoms2: list ''' atoms1 = self._atoms[:] # shallow copy atoms2 = list() if len(self._atoms) <= 1: return atoms1 if len(self._atoms) > 1: # save the multiplier value as a string type of scientific notation for entry in self._atoms: assert isinstance(entry, str), 'oops' # format example: 3.2*O-18, or 3*O or O or O-16 tmp = entry.split('*') multiplier = 0.0 if len(tmp) == 1: continue elif len(tmp) == 2: multiplier = float(tmp[0]) else: assert False assert multiplier != 0.0, 'multiplier = %r' % (multiplier) multiplier = '{0:9.3e}'.format(multiplier) atoms1[self._atoms.index(entry)] = multiplier + '*' + tmp[1] # order in decreasing order of multiplier magnitude multipliers_lst = list() for entry in atoms1: tmp = entry.split('*') multiplier = 0.0 if len(tmp) == 1: continue elif len(tmp) == 2: multiplier = float(tmp[0]) else: assert False multipliers_lst.append(float(multiplier)) sortedAtoms_lst = [a for (i, a) in sorted(zip(multipliers_lst, atoms1), key=lambda pair: pair[0], reverse=True)] atoms2 = sortedAtoms_lst return atoms2
#============================= end class Specie ==================================