コード例 #1
0
 def default(self, obj):
     quantities.set_default_units(time='s', current='A')
     if isinstance(obj, quantities.quantity.Quantity):
         return float(obj.simplified.magnitude)
     elif isinstance(obj, numbers.Number):
         # Noticed Sciunit does not use always quantities,
         # this will avoid the entire UI to explode
         return float(obj)
     else:
         db_logger.exception(f"I do not know this unit: {obj}")
コード例 #2
0
ファイル: units.py プロジェクト: Franculino/VGM
def scaling_factor_du(Q_rescale, defaultUnits):
    """Computes the scaling factor to multiply a quantity with, if it is to be
    expressed in the default units provided.
    INPUT: Q_rescale: The quantity instance or unit-string that is to be 
           rescaled.
           defaultUnits: The default units as dictionary, e.g.: {'length': 'm', 
                         'mass': 'kg', 'time': 's'}
    OUTPUT: Factor by which Q_rescale is to be multiplied with, if expressed in
            the default units.
    """
    pq.set_default_units(**defaultUnits)
    if not isinstance(Q_rescale, pq.Quantity):
        Q_rescale = pq.Quantity(1.0, Q_rescale)
    return Q_rescale.simplified.magnitude.tolist()    
コード例 #3
0
def scaling_factor_du(Q_rescale, defaultUnits):
    """Computes the scaling factor to multiply a quantity with, if it is to be
    expressed in the default units provided.
    INPUT: Q_rescale: The quantity instance or unit-string that is to be 
           rescaled.
           defaultUnits: The default units as dictionary, e.g.: {'length': 'm', 
                         'mass': 'kg', 'time': 's'}
    OUTPUT: Factor by which Q_rescale is to be multiplied with, if expressed in
            the default units.
    """
    pq.set_default_units(**defaultUnits)
    if not isinstance(Q_rescale, pq.Quantity):
        Q_rescale = pq.Quantity(1.0, Q_rescale)
    return Q_rescale.simplified.magnitude.tolist()
コード例 #4
0
ファイル: input.py プロジェクト: rwest/MEASURE
#   The above copyright notice and this permission notice shall be included in
#   all copies or substantial portions of the Software.
#
#   THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
#   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
#   DEALINGS IN THE SOFTWARE.
#
################################################################################

import logging
import quantities
quantities.set_default_units('si')
quantities.UnitQuantity('kilocalorie', 1000.0*quantities.cal, symbol='kcal')

from chempy.species import Species, TransitionState
from chempy.reaction import Reaction
from chempy.species import LennardJones as LennardJonesModel
from chempy.states import *
from chempy.kinetics import ArrheniusModel

from network import Network
from collision import SingleExponentialDownModel

################################################################################

# The current network
network = None
コード例 #5
0
"""

import logging

import cython
import numpy as np
import quantities as pq

import rmgpy.constants as constants
from rmgpy.exceptions import QuantityError
from rmgpy.rmgobject import RMGObject, expand_to_dict

################################################################################

# Explicitly set the default units to SI
pq.set_default_units('si')

# These units are not defined by the quantities package, but occur frequently
# in data handled by RMG, so we define them manually
pq.UnitQuantity('kilocalories', pq.cal * 1e3, symbol='kcal')
pq.UnitQuantity('kilojoules', pq.J * 1e3, symbol='kJ')
pq.UnitQuantity('kilomoles', pq.mol * 1e3, symbol='kmol')
pq.UnitQuantity('molecule', pq.mol / 6.02214179e23, symbol='molecule')
pq.UnitQuantity('molecules', pq.mol / 6.02214179e23, symbol='molecules')
pq.UnitQuantity('debye', 1.0 / (constants.c * 1e21) * pq.C * pq.m, symbol='De')

################################################################################

# Units that should not be used in RMG-Py:
NOT_IMPLEMENTED_UNITS = ['degC', 'C', 'degF', 'F', 'degR', 'R']
コード例 #6
0
	sys.exit(0)

# User adjustable parameters
if args.nwalkers == -1:
	nwalkers = 64
else:
	nwalkers = args.nwalkers
if args.nsteps == -1:
	nsteps = 1000
else:
	nsteps = args.nsteps
nburn = nsteps/2
t0 = 1.e5

# Constants and units
pq.set_default_units('cgs')

G = pq.constants.G.simplified.magnitude
pc = pq.pc.simplified.magnitude
au = pq.au.simplified.magnitude
yr = pq.year.simplified.magnitude
kpc = 1.e3*pc
mpc = 1.e-3*pc
impc = 1./mpc
km = 1.e5
ikm = 1./km
msun = 1.9891e33
asec = 2.*3600.*180./np.pi
iasec = 1./asec
masec = 1.e3*asec
imasec = 1./masec
コード例 #7
0
ファイル: quantity.py プロジェクト: Lyle-zhang/RMG-Py
################################################################################

"""
This module contains classes and methods for working with physical quantities,
particularly the :class:`Quantity` class for representing physical quantities.
"""

import numpy
import quantities as pq

import rmgpy.constants as constants

################################################################################

# Explicitly set the default units to SI
pq.set_default_units('si')

# These units are not defined by the quantities package, but occur frequently
# in data handled by RMG, so we define them manually
pq.UnitQuantity('kilocalories', pq.cal*1e3, symbol='kcal')
pq.UnitQuantity('kilojoules', pq.J*1e3, symbol='kJ')
pq.UnitQuantity('kilomoles', pq.mol*1e3, symbol='kmol')
pq.UnitQuantity('molecule', pq.mol/6.02214179e23, symbol='molecule')
pq.UnitQuantity('molecules', pq.mol/6.02214179e23, symbol='molecules')
pq.UnitQuantity('debye', 1.0/(constants.c*1e21)*pq.C*pq.m, symbol='De')

################################################################################

# Units that should not be used in RMG-Py:
NOT_IMPLEMENTED_UNITS = [
                        'degC',
コード例 #8
0
ファイル: io.py プロジェクト: athlonshi/RMG-Py
def readInputFile(fstr):
	"""
	Parse an RMG input file at the location `fstr`. If successful, this 
	function returns a :class:`rmg.model.CoreEdgeReactionModel` object and a 
	list of one or more :class:`rmg.model.ReactionSystem` objects.
	"""

	try:
		
		# Parse the RMG input XML file into a DOM tree
		xml0 = XML(path=fstr)

		# Make sure root element is a <rmginput> element
		rootElement = xml0.getRootElement()
		if rootElement.tagName != 'rmginput':
			raise InvalidInputFileException('Incorrect root element; should be <rmginput>.')
		
		# Process option list
		optionList = xml0.getChildElement(rootElement, 'optionList')
		# Process units option
		units = xml0.getChildElementText(optionList, 'units', required=False, default='si')
		pq.set_default_units(units)
		# Read draw molecules option
		drawMolecules = xml0.getChildElement(optionList, 'drawMolecules', required=False)
		settings.drawMolecules = (drawMolecules is not None)
		# Read generate plots option
		generatePlots = xml0.getChildElement(optionList, 'generatePlots', required=False)
		settings.generatePlots = (generatePlots is not None)
		# Read spectral data estimation option
		spectralDataEstimation = xml0.getChildElement(optionList, 'spectralDataEstimation', required=False)
		settings.spectralDataEstimation = (spectralDataEstimation is not None)

		# Read unimolecular reaction network option
		unirxnNetworks = xml0.getChildElement(optionList, 'unimolecularReactionNetworks', required=False)
		if unirxnNetworks is not None:
			# Read method
			method = str(xml0.getChildElementText(unirxnNetworks, 'method', required=True))
			allowed = ['modifiedstrongcollision', 'reservoirstate']
			if method.lower() not in allowed:
				raise InvalidInputFileException('Invalid unimolecular reaction networks method "%s"; allowed values are %s.' % (method, allowed))
			# Read temperatures
			temperatures = xml0.getChildQuantity(unirxnNetworks, 'temperatures', required=False,
				default=pq.Quantity([300.0, 400.0, 500.0, 600.0, 800.0, 1000.0, 1500.0, 2000.0], 'K'))
			temperatures = [float(T.simplified) for T in temperatures]
			# Read pressures
			pressures = xml0.getChildQuantity(unirxnNetworks, 'pressures', required=False,
				default=pq.Quantity([1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7], 'Pa'))
			pressures = [float(P.simplified) for P in pressures]
			# Read grain size
			grainSize = xml0.getChildQuantity(unirxnNetworks, 'grainSize', required=False,
				default=pq.Quantity(0.0, 'J/mol'))
			grainSize = float(grainSize.simplified)
			# Read number of grains
			numberOfGrains = int(xml0.getChildElementText(unirxnNetworks, 'numberOfGrains', required=False, default=0))
			if grainSize == 0.0 and numberOfGrains == 0:
				raise InvalidInputFileException('Must specify a grain size or number of grains for unimolecular reaction networks calculations.')
			# Read interpolation model
			interpolationModel = xml0.getChildElement(unirxnNetworks, 'interpolationModel', required=True)
			modelType = str(xml0.getAttribute(interpolationModel, 'type', required=True))
			allowed = ['none', 'chebyshev', 'pdeparrhenius']
			if modelType.lower() not in allowed:
				raise InvalidInputFileException('Invalid unimolecular reaction networks interpolation model "%s"; allowed values are %s.' % (method, allowed))
			if modelType.lower() == 'chebyshev':
				numTPolys = int(xml0.getChildElementText(interpolationModel, 'numberOfTemperaturePolynomials', required=False, default='4'))
				numPPolys = int(xml0.getChildElementText(interpolationModel, 'numberOfPressurePolynomials', required=False, default='4'))
				interpolationModel = (modelType, numTPolys, numPPolys)
			else:
				interpolationModel = (modelType)
			settings.unimolecularReactionNetworks = (method, temperatures, pressures, grainSize, numberOfGrains, interpolationModel)
		else:
			settings.unimolecularReactionNetworks = None

		# Create an empty reaction model
		reactionModel = model.CoreEdgeReactionModel()

		# Load databases
		databases = readDatabaseList(xml0, rootElement)
		for database in databases:
			if database[1] == 'general':
				logging.verbose('General database: ' + database[2])
				# Load all databases
				loadThermoDatabase(database[2] + os.sep)
				loadKineticsDatabase(database[2] + os.sep)
				loadFrequencyDatabase(database[2])
			elif database[1] == 'seedmechanism':
				logging.verbose('Seed mechanism: ' + database[2])
				reactionModel.loadSeedMechanism(database[2])
			logging.verbose('')
			
		# Process species
		coreSpecies = []; speciesDict = {}
		speciesList = xml0.getChildElement(rootElement, 'speciesList')
		speciesElements = xml0.getChildElements(speciesList, 'species')
		logging.info('Found ' + str(len(speciesElements)) + ' species')
		for element in speciesElements:
			
			# Load species ID
			sid = str(xml0.getAttribute(element, 'id', required=True))

			# Load the species data from the file
			spec = species.Species()
			spec.fromXML(xml0, element)

			# Check that the species isn't already in the core (e.g. from a seed mechanism)
			existingSpecies = None
			for s in reactionModel.core.species:
				if s.isIsomorphic(spec):
					existingSpecies = s
					break

			if existingSpecies is not None:
				# Point to existing species rather than newly created species
				# This means that any information about the species in the
				# input file will be discarded in favor of the existing species
				# data
				spec = existingSpecies
			else:
				# Handle other aspects of RMG species creation
				logging.verbose('Creating new species %s' % str(spec))
				species.processNewSpecies(spec)

			# All species in RMG input file are immediately added to the core
			coreSpecies.append(spec)

			# Add to local species dictionary (for matching with other parts of file)
			speciesDict[sid] = spec

		logging.verbose('')
		
		# Read model flux tolerance
		fluxTolerance = xml0.getChildElement(rootElement, 'fluxTolerance')
		reactionModel.fluxToleranceKeepInEdge = float(xml0.getChildElementText(fluxTolerance, 'keepInEdge'))
		reactionModel.fluxToleranceMoveToCore = float(xml0.getChildElementText(fluxTolerance, 'moveToCore'))
		reactionModel.fluxToleranceInterrupt = float(xml0.getChildElementText(fluxTolerance, 'interruptSimulation'))
		
		logging.debug('Model flux tolerances set to:')
		logging.debug('\tKeep in edge:         %s' % (reactionModel.fluxToleranceKeepInEdge) )
		logging.debug('\tMove to core:         %s' % (reactionModel.fluxToleranceMoveToCore) )
		logging.debug('\tInterrupt simulation: %s' % (reactionModel.fluxToleranceInterrupt) )
		logging.debug('')
		
		# Read maximum model size
		maxModelSize = xml0.getChildElement(rootElement, 'maximumModelSize')
		if maxModelSize is None:
			logging.debug('Maximum model size is not set')
		else:
			reactionModel.maximumEdgeSpecies = int(xml0.getChildElementText(maxModelSize, 'edgeSpecies'))
			logging.debug('Maximum model size set to:')
			logging.debug('\tEdge species:         %s' % (reactionModel.maximumEdgeSpecies) )
		logging.debug('')

		# Read dynamic simulator
		element = xml0.getChildElement(rootElement, 'simulator')
		reactionModel.absoluteTolerance = float(xml0.getAttribute(element, 'atol'))
		reactionModel.relativeTolerance = float(xml0.getAttribute(element, 'rtol'))
		logging.info('Read dynamic simulator')
		logging.debug('Simulator:')
		logging.debug('\tAbsolute tolerance set to %s' % (reactionModel.absoluteTolerance))
		logging.debug('\tRelative tolerance set to %s' % (reactionModel.relativeTolerance))
		logging.debug('')

		# Read termination targets
		termination = xml0.getChildElement(rootElement, 'termination')
		targetElements = xml0.getChildElements(termination, 'target')
		for element in targetElements:

			targetType = xml0.getAttribute(element, 'type')
			if targetType == 'conversion':
				sid = xml0.getAttribute(element, 'speciesID')
				spec = speciesDict[sid]
				conv = float(xml0.getElementText(element))
				if conv < 0.0 or conv > 1.0:
					raise InvalidInputFileException('Invalid value for termination fractional conversion.')
				reactionModel.termination.append(model.TerminationConversion(spec, conv))
			elif targetType == 'time':
				units = str(xml0.getAttribute(element, 'units'))
				time = float(xml0.getElementText(element))
				time = pq.Quantity(time, units); time = float(time.simplified)
				if time < 0.0:
					raise InvalidInputFileException('Invalid value for termination time.')
				reactionModel.termination.append(model.TerminationTime(time))
			else:
				raise InvalidInputFileException('Invalid termination target type "'+targetType+'".')
		if len(reactionModel.termination) == 0:
			raise InvalidInputFileException('No termination targets specified.')

		# Output info about termination targets
		if len(reactionModel.termination) == 1:
			logging.info('Found ' + str(len(reactionModel.termination)) + ' termination target')
		else:
			logging.info('Found ' + str(len(reactionModel.termination)) + ' termination targets')
		for index, target in enumerate(reactionModel.termination):
			string = '\tTermination target #' + str(index+1) + ': '
			if target.__class__ == model.TerminationConversion:
				string += 'conversion ' + str(target.species) + ' ' + str(target.conversion)
			elif target.__class__ == model.TerminationTime:
				string += 'time ' + str(target.time)
			logging.debug(string)	
				
		logging.debug('')

		# Get list of available reaction systems
		import system as systemModule
		availableSystems = systemModule.getAvailableReactionSystems()
		
		# Process reaction systems
		reactionSystems = []
		reactionSystemList = xml0.getChildElement(rootElement, 'reactionSystemList')
		systemElements = xml0.getChildElements(reactionSystemList, 'reactionSystem')
		for systemElement in systemElements:
		
			# Determine the class of reaction system
			rsClass = xml0.getAttribute(systemElement, 'class')
			if rsClass not in availableSystems:
				raise InvalidInputFileException('Reaction system class "%s" not available.' % (rsClass))
		
			# Declare the reaction system and populate it with info
			reactionSystem = availableSystems[rsClass]()
			reactionSystem.fromXML(xml0, systemElement, speciesDict)
			reactionSystem.initializeCantera()
			
			# Append to the list of reaction systems
			reactionSystems.append(reactionSystem)

		# Output info about reaction system
		if len(reactionSystems) == 1:
			logging.info('Found ' + str(len(reactionSystems)) + ' reaction system')
		else:
			logging.info('Found ' + str(len(reactionSystems)) + ' reaction systems')
		for index, reactionSystem in enumerate(reactionSystems):
			logging.debug('Reaction system #%i: %s' % (index+1, reactionSystem))
				
		logging.debug('')
			
		# Cleanup the DOM tree when finished
		xml0.cleanup()
		
	except InvalidInputFileException, e:
		logging.exception(str(e))
		raise e
コード例 #9
0
ファイル: quantity.py プロジェクト: jwallen/RMG-Py
################################################################################

"""
This module contains classes and methods for working with physical quantities,
particularly the :class:`Quantity` class for representing physical quantities.
"""

import numpy
import quantities as pq

import rmgpy.constants as constants

################################################################################

# Explicitly set the default units to SI
pq.set_default_units("si")

# These units are not defined by the quantities package, but occur frequently
# in data handled by RMG, so we define them manually
pq.UnitQuantity("kilocalories", pq.cal * 1e3, symbol="kcal")
pq.UnitQuantity("kilojoules", pq.J * 1e3, symbol="kJ")
pq.UnitQuantity("kilomoles", pq.mol * 1e3, symbol="kmol")
pq.UnitQuantity("molecule", pq.mol / 6.02214179e23, symbol="molecule")
pq.UnitQuantity("molecules", pq.mol / 6.02214179e23, symbol="molecules")
pq.UnitQuantity("debye", 1.0 / (constants.c * 1e21) * pq.C * pq.m, symbol="De")

################################################################################


class QuantityError(Exception):
    """
コード例 #10
0
ファイル: io.py プロジェクト: raphaelshirley/RMG-Py
def readInputFile(fstr):
	"""
	Parse an RMG input file at the location `fstr`. If successful, this 
	function returns a :class:`rmg.model.CoreEdgeReactionModel` object and a 
	list of one or more :class:`rmg.model.ReactionSystem` objects.
	"""

	try:
		
		# Parse the RMG input XML file into a DOM tree
		xml0 = XML(path=fstr)

		# Make sure root element is a <rmginput> element
		rootElement = xml0.getRootElement()
		if rootElement.tagName != 'rmginput':
			raise InvalidInputFileException('Incorrect root element; should be <rmginput>.')
		
		# Process units
		units = xml0.getChildElementText(rootElement, 'units', required=False, default='si')
		pq.set_default_units(units)

		# Read draw molecules option
		drawMolecules = xml0.getChildElementText(rootElement, 'drawMolecules', required=False, default='off')
		drawMolecules = drawMolecules.lower()
		settings.drawMolecules = (drawMolecules == 'on' or drawMolecules == 'true' or drawMolecules == 'yes')
		
		# Read generate plots option
		generatePlots = xml0.getChildElementText(rootElement, 'generatePlots', required=False, default='off')
		generatePlots = generatePlots.lower()
		settings.generatePlots = (generatePlots == 'on' or generatePlots == 'true' or generatePlots == 'yes')

		# Process databases
		databases = []
		databaseElements = xml0.getChildElements(rootElement, 'database')
		for element in databaseElements:
			
			# Get database type
			databaseType = xml0.getAttribute(element, 'type', required=True)
			databaseType = databaseType.lower()
			if databaseType != 'general':
				raise InvalidInputFileException('Invalid database type "' + databaseType + '"; valid types are "general".')
			
			# Get database name and form path
			databaseName = xml0.getElementText(element)
			databasePath = os.path.dirname(__file__)
			databasePath = os.path.join(databasePath, '..')
			databasePath = os.path.join(databasePath, '..')
			databasePath = os.path.join(databasePath, 'data')
			databasePath = os.path.join(databasePath, databaseName)
			if not os.path.exists(databasePath):
				raise InvalidInputFileException('Database "%s" not found.' % databaseName)
			
			databases.append([databaseName, databaseType, databasePath])
		
		# Output info about databases
		logging.info('Found %s database%s' % (len(databases), 's' if len(databases) > 1 else ''))
		
		# Check that exactly one general database was specified
		generalDatabaseCount = sum([1 for database in databases if database[1] == 'general'])
		if generalDatabaseCount == 0:
			raise InvalidInputFileException('No general database specified; one must be present.')
		elif generalDatabaseCount > 1:
			raise InvalidInputFileException('Multiple general databases specified; only one is allowed.')

		# Load databases
		for database in databases:
			if database[1] == 'general':
				logging.debug('General database: ' + database[2])
				# Load thermo databases
				species.thermoDatabase = species.ThermoDatabaseSet()
				species.thermoDatabase.load(database[2] + os.sep)
				# Load forbidden structures
				thermo.forbiddenStructures = data.Dictionary()
				thermo.forbiddenStructures.load(database[2] + os.sep + 'forbiddenStructure.txt')
				thermo.forbiddenStructures.toStructure()
				# Load kinetic databases (reaction families)
				reaction.kineticsDatabase = reaction.ReactionFamilySet()
				reaction.kineticsDatabase.load(database[2] + os.sep)
				
		logging.debug('')
		
		# Process species
		coreSpecies = []; speciesDict = {}
		speciesElements = xml0.getChildElements(rootElement, 'species')
		logging.info('Found ' + str(len(speciesElements)) + ' species')
		for element in speciesElements:
			
			# Attributes of the species element
			sid = xml0.getAttribute(element, 'id')
			label = xml0.getAttribute(element, 'label')
			reactive = xml0.getAttribute(element, 'reactive', required=False, default='yes')
			reactive = reactive.lower()
			reactive = not (reactive == 'no' or reactive == 'false' or reactive == 'n')
			
			# Load structure
			struct = structure.Structure()
			
			cml = xml0.getChildElement(element, 'cml', required=False)
			inchi = xml0.getChildElement(element, 'inchi', required=False)
			smiles = xml0.getChildElement(element, 'smiles', required=False)
			if cml is not None:
				cmlstr = str(xml0.getChildElement(cml, 'molecule', required=True).toxml())
				struct.fromCML(cmlstr)
			elif inchi is not None:
				inchistr = str(xml0.getElementText(inchi))
				struct.fromInChI(inchistr)
			elif smiles is not None:
				smilesstr = str(xml0.getElementText(smiles))
				struct.fromSMILES(smilesstr)
			else:
				raise InvalidInputFileException('Species "%s" missing structure information.' % label)
			
			# Create a new species and append the species to the core
			spec = species.makeNewSpecies(struct, label, reactive)
			coreSpecies.append(spec)
			
			# Add to local species dictionary (for matching with other parts of file)
			speciesDict[sid] = spec

		logging.debug('')
		
		# Create an empty reaction model
		reactionModel = model.CoreEdgeReactionModel()
		
		# Read model flux tolerance
		fluxTolerance = xml0.getChildElement(rootElement, 'fluxTolerance')
		reactionModel.fluxToleranceKeepInEdge = float(xml0.getChildElementText(fluxTolerance, 'keepInEdge'))
		reactionModel.fluxToleranceMoveToCore = float(xml0.getChildElementText(fluxTolerance, 'moveToCore'))
		reactionModel.fluxToleranceInterrupt = float(xml0.getChildElementText(fluxTolerance, 'interruptSimulation'))
		
		logging.debug('Model flux tolerances set to:')
		logging.debug('\tKeep in edge:         %s' % (reactionModel.fluxToleranceKeepInEdge) )
		logging.debug('\tMove to core:         %s' % (reactionModel.fluxToleranceMoveToCore) )
		logging.debug('\tInterrupt simulation: %s' % (reactionModel.fluxToleranceInterrupt) )
		logging.debug('')
		
		# Read maximum model size
		maxModelSize = xml0.getChildElement(rootElement, 'maximumModelSize')
		if maxModelSize is None:
			logging.debug('Maximum model size is not set')
		else:
			reactionModel.maximumEdgeSpecies = int(xml0.getChildElementText(maxModelSize, 'edgeSpecies'))
			logging.debug('Maximum model size set to:')
			logging.debug('\tEdge species:         %s' % (reactionModel.maximumEdgeSpecies) )
		logging.debug('')

		# Read dynamic simulator
		element = xml0.getChildElement(rootElement, 'simulator')
		reactionModel.absoluteTolerance = float(xml0.getAttribute(element, 'atol'))
		reactionModel.relativeTolerance = float(xml0.getAttribute(element, 'rtol'))
		logging.info('Read dynamic simulator')
		logging.debug('Simulator:')
		logging.debug('\tAbsolute tolerance set to %s' % (reactionModel.absoluteTolerance))
		logging.debug('\tRelative tolerance set to %s' % (reactionModel.relativeTolerance))
		logging.debug('')

		# Read termination targets
		termination = xml0.getChildElement(rootElement, 'termination')
		targetElements = xml0.getChildElements(termination, 'target')
		for element in targetElements:

			targetType = xml0.getAttribute(element, 'type')
			if targetType == 'conversion':
				sid = xml0.getAttribute(element, 'speciesID')
				spec = speciesDict[sid]
				conv = float(xml0.getElementText(element))
				if conv < 0.0 or conv > 1.0:
					raise InvalidInputFileException('Invalid value for termination fractional conversion.')
				reactionModel.termination.append(model.TerminationConversion(spec, conv))
			elif targetType == 'time':
				units = str(xml0.getAttribute(element, 'units'))
				time = float(xml0.getElementText(element))
				time = pq.Quantity(time, units); time = float(time.simplified)
				if time < 0.0:
					raise InvalidInputFileException('Invalid value for termination time.')
				reactionModel.termination.append(model.TerminationTime(time))
			else:
				raise InvalidInputFileException('Invalid termination target type "'+targetType+'".')
		if len(reactionModel.termination) == 0:
			raise InvalidInputFileException('No termination targets specified.')

		# Output info about termination targets
		if len(reactionModel.termination) == 1:
			logging.info('Found ' + str(len(reactionModel.termination)) + ' termination target')
		else:
			logging.info('Found ' + str(len(reactionModel.termination)) + ' termination targets')
		for index, target in enumerate(reactionModel.termination):
			string = '\tTermination target #' + str(index+1) + ': '
			if target.__class__ == model.TerminationConversion:
				string += 'conversion ' + str(target.species) + ' ' + str(target.conversion)
			elif target.__class__ == model.TerminationTime:
				string += 'time ' + str(target.time)
			logging.debug(string)	
				
		logging.debug('')

		# Process reaction systems
		reactionSystems = []
		systemElements = xml0.getChildElements(rootElement, 'reactionSystem')
		for element in systemElements:
		
			# Create a new reaction system
			rsType = xml0.getAttribute(element, 'type')
			if rsType == 'batch':
				reactionSystem = model.BatchReactor()
			else:
				raise InvalidInputFileException('Invalid reaction system type "' + rsType + '".')
			
			# Temperature model
			temperatureModel = xml0.getChildElement(element, 'temperatureModel')
			tempModelType = xml0.getAttribute(temperatureModel, 'type')
			if tempModelType == 'isothermal':
				
				# Read the (constant) temperature from the file
				temperature = xml0.getChildElement(temperatureModel, 'temperature')
				value = float(xml0.getElementText(temperature))
				units = str(xml0.getAttribute(temperature, 'units'))
				T = pq.Quantity(value, units); T = float(T.simplified)
				
				# Set the reaction system's temperature model to isothermal
				reactionSystem.temperatureModel = model.TemperatureModel()
				reactionSystem.temperatureModel.setIsothermal(T)
				
			else:
				raise InvalidInputFileException('Invalid temperature model type "' + tempModelType + '".')
			
			# Pressure model
			pressureModel = xml0.getChildElement(element, 'pressureModel')
			pressModelType = xml0.getAttribute(pressureModel, 'type')
			if pressModelType == 'isobaric':
				
				# Read the (constant) pressure from the file
				pressure = xml0.getChildElement(pressureModel, 'pressure')
				value = float(xml0.getElementText(pressure))
				units = str(xml0.getAttribute(pressure, 'units'))
				P = pq.Quantity(value, units); P = float(P.simplified)
				
				# Set the reaction system's pressure model to isobaric
				reactionSystem.pressureModel = model.PressureModel()
				reactionSystem.pressureModel.setIsobaric(P)
				
			else:
				raise InvalidInputFileException('Invalid pressure model type "' + pressModelType + '".')

			# Physical property model
			propModel = xml0.getChildElement(element, 'physicalPropertyModel')
			propModelType = xml0.getAttribute(propModel, 'type')
			if propModelType.lower() == 'idealgas':
				# Set the reaction system's pressure model to isobaric
				reactionSystem.equationOfState = model.IdealGas()
			elif propModelType.lower() == 'incompressibleliquid':
				molarVolume = xml0.getFirstChildElement(element, 'molarVolume')
				value = float(xml0.getElementText(molarVolume))
				units = str(xml0.getAttribute(molarVolume, 'units'))
				Vmol = float(pq.Quantity(value, units).simplified); 
				
				reactionSystem.equationOfState = model.IncompressibleLiquid( 
					P = reactionSystem.pressureModel.getPressure(),
					T = reactionSystem.temperatureModel.getTemperature(),
					Vmol = Vmol
					)
			else:
				raise InvalidInputFileException('Invalid physical property model type "' + propModelType + '".')

			# Get total concentration
			T = reactionSystem.temperatureModel.getTemperature(0)
			P = reactionSystem.pressureModel.getPressure(0)
			totalConc = 1.0 / reactionSystem.equationOfState.getVolume(T, P, [1.0])

			# Initialize all initial concentrations to zero
			for spec in coreSpecies:
				reactionSystem.initialConcentration[spec] = 0.0
			
			# List of initial concentrations
			moleFractions = xml0.getChildElements(element, 'moleFraction')
			for moleFraction in moleFractions:
			
				# Read the concentration from the file
				value = float(xml0.getElementText(moleFraction))
				sid = xml0.getAttribute(moleFraction, 'speciesID')
				
				reactionSystem.initialConcentration[speciesDict[sid]] = value * totalConc
			
			# Append to list of reaction systems
			reactionSystems.append(reactionSystem)
		
		# Output info about reaction system
		if len(reactionSystems) == 1:
			logging.info('Found ' + str(len(reactionSystems)) + ' reaction system')
		else:
			logging.info('Found ' + str(len(reactionSystems)) + ' reaction systems')
		for index, reactionSystem in enumerate(reactionSystems):
			logging.debug('Reaction system #' + str(index+1) + ':')
			logging.debug('\t' + str(reactionSystem.temperatureModel))
			logging.debug('\t' + str(reactionSystem.pressureModel))
			for spec, conc in reactionSystem.initialConcentration.iteritems():
				if spec.reactive:
					logging.debug('\tInitial concentration of ' + str(spec) + ': ' + str(conc))
				else:
					logging.debug('\tConstant concentration of ' + str(spec) + ': ' + str(conc))
				
				
		logging.debug('')
			
		# Cleanup the DOM tree when finished
		xml0.cleanup()
		
	except InvalidInputFileException, e:
		logging.exception(str(e))
		raise e