def calc_Rf(spc_i, reactions, reactant_or_product, T, P, coreSpeciesConcentrations, formation_or_consumption): """ Calculates the total rate of formation/consumption of species i. Computes the sum of the rates of formation/consumption of spc_i for all of the reactions in which spc_i is a product. if formation_or_consumption == 'formation', spc_i will be compared to the products of the reaction. Else, spc_i will be compared to the reactants of the reaction. units of rate: mol/(m^3.s) """ rate = 0.0 for reaction in reactions: molecules = reaction.products if formation_or_consumption == 'formation:' else reaction.reactants labels = [mol.label for mol in molecules] if spc_i.label in labels: rij = calc_rij(reaction, spc_i, reactant_or_product, T, P, coreSpeciesConcentrations) rate = rate + rij logging.debug('Rf: {rate}'.format(**locals())) return rate
def assess_reaction(rxn, reactionSystems, tolerance, data): """ Returns whether the reaction is important or not in the reactions. It iterates over the reaction systems, and loads the concentration profile of each reaction system into memory. It iterates over a number of samples in profile and evaluates the importance of the reaction at every sample. """ logging.debug('Assessing reaction {}'.format(rxn)) reactions = shared.getConst('reactions') # read in the intermediate state variables for datum, reactionSystem in zip(data, reactionSystems): T, P = reactionSystem.T.value_si, reactionSystem.P.value_si species_names, profile = datum # take N evenly spaced indices from the table with simulation results: """ Number of time steps between start and end time of the batch reactor simulation at which the importance of reactions should be evaluated. The more timesteps, the less chance we have to remove an important reactions, but the more simulations need to be carried out. """ timesteps = len(profile) / 2 logging.debug('Evaluating the importance of a reaction at {} time samples.'.format(timesteps)) assert timesteps <= len(profile) indices = map(int, np.linspace(0, len(profile)-1, num = timesteps)) for index in indices: assert profile[index] is not None timepoint, coreSpeciesConcentrations = profile[index] coreSpeciesConcentrations = {key: float(value) for (key, value) in zip(species_names, coreSpeciesConcentrations)} # print 'Species concentrations at {}: {}'.format(timepoint, reactionSystem.coreSpeciesConcentrations) for species_i in rxn.reactants: if isImportant(rxn, species_i, reactions, 'reactant', tolerance, T, P, coreSpeciesConcentrations): return True #only continue if the reaction is not important yet. for species_i in rxn.products: if isImportant(rxn, species_i, reactions, 'product', tolerance, T, P, coreSpeciesConcentrations): return True return False
def isImportant(rxn, species_i, reactions, reactant_or_product, tolerance, T, P, coreSpeciesConcentrations): """ This function computes: - Ri = R(species_i) - rij = r(rxn) - alpha = ratio of rij / Ri Range of values of alpha: 0 <= alpha <= 1 This function also compares alpha to a user-defined tolerance TOLERANCE. if alpha >= tolerance: this reaction is important for this species. else: this reaction is unimportant for this species. Returns whether or not rxn is important for species_i. keep = True remove = False """ #calc Ri, where i = species rij = calc_rij(rxn, species_i, reactant_or_product, T, P, coreSpeciesConcentrations) Ri = calc_Ri(species_i, rij, reactions, reactant_or_product, T, P, coreSpeciesConcentrations) logging.debug("rij: {rij}, Ri: {Ri}, rxn: {rxn}, species: {species_i}, reactant: {reactant_or_product}, tol: {tolerance}"\ .format(**locals())) if np.any(np.absolute([rij, Ri]) < CLOSE_TO_ZERO): return False else: assert Ri != 0, "rij: {0}, Ri: {1}, rxn: {2}, species: {3}, reactant: {4}".format( rij, Ri, rxn, species_i, reactant_or_product) alpha = rij / Ri if alpha < 0: return False if alpha > tolerance: """ If both values are very close to 1, then the comparison of alpha and the tolerance might sometimes return an unexpected value. When we set the tolerance to a value of 1, we want all the reactions to be unimportant, regardless of the value of alpha. """ if np.allclose([tolerance, alpha], [1.0, 1.0]): return False # print "rij: {0}, Ri: {1}, rxn: {2}, species: {3}, reactant: {4}, alpha: {5}, tolerance: {6}"\ # .format(rij, Ri, rxn_j, species_i, reactant_or_product, alpha, tolerance) return True #where tolerance is user specified tolerance elif alpha <= tolerance: return False
def isImportant(rxn, species_i, reactions, reactant_or_product, tolerance, T, P, coreSpeciesConcentrations): """ This function computes: - Ri = R(species_i) - rij = r(rxn) - alpha = ratio of rij / Ri Range of values of alpha: 0 <= alpha <= 1 This function also compares alpha to a user-defined tolerance TOLERANCE. if alpha >= tolerance: this reaction is important for this species. else: this reaction is unimportant for this species. Returns whether or not rxn is important for species_i. keep = True remove = False """ #calc Ri, where i = species rij = calc_rij(rxn, species_i, reactant_or_product, T, P, coreSpeciesConcentrations) Ri = calc_Ri(species_i, rij, reactions, reactant_or_product, T, P, coreSpeciesConcentrations) logging.debug("rij: {rij}, Ri: {Ri}, rxn: {rxn}, species: {species_i}, reactant: {reactant_or_product}, tol: {tolerance}"\ .format(**locals())) if np.any(np.absolute([rij, Ri]) < CLOSE_TO_ZERO): return False else: assert Ri != 0, "rij: {0}, Ri: {1}, rxn: {2}, species: {3}, reactant: {4}".format(rij, Ri, rxn, species_i, reactant_or_product) alpha = rij / Ri if alpha < 0: return False if alpha > tolerance : """ If both values are very close to 1, then the comparison of alpha and the tolerance might sometimes return an unexpected value. When we set the tolerance to a value of 1, we want all the reactions to be unimportant, regardless of the value of alpha. """ if np.allclose([tolerance, alpha], [1.0, 1.0]): return False # print "rij: {0}, Ri: {1}, rxn: {2}, species: {3}, reactant: {4}, alpha: {5}, tolerance: {6}"\ # .format(rij, Ri, rxn_j, species_i, reactant_or_product, alpha, tolerance) return True #where tolerance is user specified tolerance elif alpha <= tolerance: return False
def get(key): """ Searches for the shared variable to retrieve identified by the parameter key. """ try: data = shared.getConst(key, timeout=1e-9) return data except NameError: """ Name error will be caught when the SCOOP library is not imported properly. """ logging.debug('SCOOP not loaded. Not retrieving the shared object with key {}'.format(key))
def find_important_reactions(rmg, tolerance): """ This function: - loops over all the species involved in a specific reaction - decides whether the specific reaction is important for the species. Whenever it is found that a reaction is important for a species, we break the species loop, and keep the reaction in the model. Returns: a list of rxns that can be removed. """ global reactions # run the simulation, creating concentration profiles for each reaction system defined in input. simdata = simulate_all(rmg) reduce_reactions = [ReductionReaction(rxn) for rxn in reactions] """ Tolerance to decide whether a reaction is unimportant for the formation/destruction of a species Tolerance is a floating point value between 0 and 1. A high tolerance means that many reactions will be deemed unimportant, and the reduced model will be drastically smaller. A low tolerance means that few reactions will be deemed unimportant, and the reduced model will only differ from the full model by a few reactions. """ CHUNKSIZE = 40 boolean_array = [] for chunk in chunks(reduce_reactions,CHUNKSIZE): N = len(chunk) partial_results = list(map_(WorkerWrapper(assess_reaction), chunk, [rmg.reactionSystems] * N, [tolerance] * N, [simdata] * N)) boolean_array.extend(partial_results) important_rxns = [] for isImport, rxn in zip(boolean_array, reduce_reactions): logging.debug('Is rxn {rxn} important? {isImport}'.format(**locals())) if isImport: important_rxns.append(rxn) return [rxn.rmg_reaction for rxn in important_rxns]
def find_important_reactions(rmg, tolerance): """ This function: - loops over all the species involved in a specific reaction - decides whether the specific reaction is important for the species. Whenever it is found that a reaction is important for a species, we break the species loop, and keep the reaction in the model. Returns: a list of rxns that can be removed. """ global reactions # run the simulation, creating concentration profiles for each reaction system defined in input. simdata = simulate_all(rmg) reduce_reactions = [ReductionReaction(rxn) for rxn in reactions] """ Tolerance to decide whether a reaction is unimportant for the formation/destruction of a species Tolerance is a floating point value between 0 and 1. A high tolerance means that many reactions will be deemed unimportant, and the reduced model will be drastically smaller. A low tolerance means that few reactions will be deemed unimportant, and the reduced model will only differ from the full model by a few reactions. """ CHUNKSIZE = 40 boolean_array = [] for chunk in chunks(reduce_reactions, CHUNKSIZE): N = len(chunk) partial_results = list( map_(WorkerWrapper(assess_reaction), chunk, [rmg.reactionSystems] * N, [tolerance] * N, [simdata] * N)) boolean_array.extend(partial_results) important_rxns = [] for isImport, rxn in zip(boolean_array, reduce_reactions): logging.debug('Is rxn {rxn} important? {isImport}'.format(**locals())) if isImport: important_rxns.append(rxn) return [rxn.rmg_reaction for rxn in important_rxns]
def broadcast(obj, key): """ Broadcasts the object across the workers using the key parameter as the key. """ kwargs = {key : obj} try: if shared.getConst(key): logging.debug('An object with the key {} was already broadcasted.'.format(key)) else: shared.setConst(**kwargs) except NameError, e: """ Name error will be caught when the SCOOP library is not imported properly. """ logging.debug('SCOOP not loaded. Not broadcasting the object {}'.format(obj))
def get(key): """ Searches for the shared variable to retrieve identified by the parameter key. """ try: data = shared.getConst(key, timeout=1e-9) return data except NameError: """ Name error will be caught when the SCOOP library is not imported properly. """ logging.debug( 'SCOOP not loaded. Not retrieving the shared object with key {}'. format(key))
def broadcast(obj, key): """ Broadcasts the object across the workers using the key parameter as the key. """ kwargs = {key: obj} try: if shared.getConst(key): logging.debug( 'An object with the key {} was already broadcasted.'.format( key)) else: shared.setConst(**kwargs) except NameError, e: """ Name error will be caught when the SCOOP library is not imported properly. """ logging.debug( 'SCOOP not loaded. Not broadcasting the object {}'.format(obj))
This module contains functionality for the parallel execution of RMG-Py. """ import sys import traceback import warnings from functools import wraps try: from scoop import futures from scoop import shared from scoop import logger as logging except ImportError: import logging as logging logging.debug("Could not properly import SCOOP.") def warnScoopStartedProperly(func): @wraps(func) def wrapper(*args, **kwargs): futures_not_loaded = 'scoop.futures' not in sys.modules warnings.simplefilter('ignore', RuntimeWarning) try: controller_not_started = not ( sys.modules['scoop.futures'].__dict__.get("_controller", None)) except KeyError, e: warnings.warn(
import signal try: import scoop scoop.DEBUG = False from scoop import futures, _control, utils, shared from scoop._types import FutureQueue from scoop.broker.structs import BrokerInfo from scoop import logger as logging except ImportError, e: import logging as logging logging.debug("Could not properly import SCOOP.") subprocesses = [] def cleanSubprocesses(): [a.kill() for a in subprocesses] try: signal.signal(signal.SIGQUIT, cleanSubprocesses) except AttributeError: # SIGQUIT doesn't exist on Windows signal.signal(signal.SIGTERM, cleanSubprocesses)
import signal try: import scoop scoop.DEBUG = False from scoop import futures, _control, utils, shared from scoop._types import FutureQueue from scoop.broker.structs import BrokerInfo from scoop import logger as logging except ImportError, e: import logging as logging logging.debug("Could not properly import SCOOP.") subprocesses = [] def cleanSubprocesses(): [a.kill() for a in subprocesses] try: signal.signal(signal.SIGQUIT, cleanSubprocesses) except AttributeError: # SIGQUIT doesn't exist on Windows signal.signal(signal.SIGTERM, cleanSubprocesses) def port_ready(port, socket): """Checks if a given port is already binded"""
This module contains functionality for the parallel execution of RMG-Py. """ import sys import traceback import warnings from functools import wraps try: from scoop import futures from scoop import shared from scoop import logger as logging except ImportError: import logging as logging logging.debug("Could not properly import SCOOP.") def warnScoopStartedProperly(func): @wraps(func) def wrapper(*args, **kwargs): futures_not_loaded = 'scoop.futures' not in sys.modules warnings.simplefilter('ignore', RuntimeWarning) try: controller_not_started = not ( sys.modules['scoop.futures'].__dict__.get("_controller", None) ) except KeyError, e: warnings.warn(
def assess_reaction(rxn, reactionSystems, tolerance, data): """ Returns whether the reaction is important or not in the reactions. It iterates over the reaction systems, and loads the concentration profile of each reaction system into memory. It iterates over a number of samples in profile and evaluates the importance of the reaction at every sample. """ logging.debug('Assessing reaction {}'.format(rxn)) reactions = shared.getConst('reactions') # read in the intermediate state variables for datum, reactionSystem in zip(data, reactionSystems): T, P = reactionSystem.T.value_si, reactionSystem.P.value_si species_names, profile = datum # take N evenly spaced indices from the table with simulation results: """ Number of time steps between start and end time of the batch reactor simulation at which the importance of reactions should be evaluated. The more timesteps, the less chance we have to remove an important reactions, but the more simulations need to be carried out. """ timesteps = len(profile) / 2 logging.debug( 'Evaluating the importance of a reaction at {} time samples.'. format(timesteps)) assert timesteps <= len(profile) indices = map(int, np.linspace(0, len(profile) - 1, num=timesteps)) for index in indices: assert profile[index] is not None timepoint, coreSpeciesConcentrations = profile[index] coreSpeciesConcentrations = { key: float(value) for (key, value) in zip(species_names, coreSpeciesConcentrations) } # print 'Species concentrations at {}: {}'.format(timepoint, reactionSystem.coreSpeciesConcentrations) for species_i in rxn.reactants: if isImportant(rxn, species_i, reactions, 'reactant', tolerance, T, P, coreSpeciesConcentrations): return True #only continue if the reaction is not important yet. for species_i in rxn.products: if isImportant(rxn, species_i, reactions, 'product', tolerance, T, P, coreSpeciesConcentrations): return True return False