Beispiel #1
0
def pfa_loop_control(solution_object, args, stored_error, threshold, done, rate_edge_data, ignition_delay_detailed, conditions_array):

    target_species = args.target

    #run detailed mechanism and retain initial conditions
    species_retained = []
    printout = ''
    print('Threshold     Species in Mech      Error')

    #run DRG and create new reduced solution
    pfa = trim_pfa(rate_edge_data, solution_object, threshold, args.keepers, done,target_species) #Find out what to cut from the model
    exclusion_list = pfa
    new_solution_objects = trim(solution_object, exclusion_list, args.data_file) #Cut the exclusion list from the model.
    species_retained.append(len(new_solution_objects[1].species()))

    #simulated reduced solution
    new_sim = helper.setup_simulations(conditions_array,new_solution_objects[1]) #Create simulation objects for reduced model for all conditions
    ignition_delay_reduced = helper.simulate(new_sim) #Run simulations and process results

    if (ignition_delay_detailed.all() == 0): #Ensure that ignition occured
        print("Original model did not ignite.  Check initial conditions.")
        exit()

    #Calculate error
    error = (abs(ignition_delay_reduced-ignition_delay_detailed)/ignition_delay_detailed)*100 #Calculate error
    printout += str(threshold) + '                 ' + str(len(new_solution_objects[1].species())) + '              '+  str(round(np.max(error), 2)) +'%' + '\n'
    print(printout)
    stored_error[0] = round(np.max(error), 2)

    #Return new model.
    new_solution_objects = new_solution_objects[1]
    return new_solution_objects
Beispiel #2
0
def run_pfa(args, solution_object,error,past):

	if len(args.target) == 0: #If the target species are not specified, puke and die.
		print("Please specify a target species.")
		exit()
	done = [] #Singleton to hold wether or not any more species can be cut from the simulation.
	done.append(False)
	threshold = .1 #Starting threshold value
	threshold_i = .1
	n = 1
	error = [10.0] #Singleton to hold the error value of the previously ran simulation.

	#Check to make sure that conditions exist
	if args.conditions_file:
		conditions_array = readin_conditions(str(args.conditions_file))
	elif not args.conditions_file:
		print("Conditions file not found")
		exit()

	sim_array = helper.setup_simulations(conditions_array,solution_object) #Turn conditions array into unran simulation objects for the original solution
	ignition_delay_detailed = helper.simulate(sim_array) #Run simulations and process results
	rate_edge_data = get_rates_pfa(sim_array, solution_object) #Get edge weight calculation data.

	print("Testing for starting threshold value")
	pfa_loop_control(solution_object, args, error, threshold, done, rate_edge_data, ignition_delay_detailed, conditions_array) #Trim the solution at that threshold and find the error.
	while error[0] != 0: #While the error for trimming with that threshold value is greater than allowed.
		threshold = threshold / 10 #Reduce the starting threshold value and try again.
		threshold_i = threshold_i / 10
		n = n + 1
		pfa_loop_control(solution_object, args, error, threshold, done, rate_edge_data, ignition_delay_detailed, conditions_array)
		if error[0] <= .02:
			error[0] = 0

	print("Starting with a threshold value of " + str(threshold))
	sol_new = solution_object
	past[0] = 0 #An integer representing the error introduced in the past simulation.
	done[0] = False

	while not done[0] and error[0] < args.error: #Run the simulation until nothing else can be cut.
		sol_new = pfa_loop_control( solution_object, args, error, threshold, done, rate_edge_data, ignition_delay_detailed, conditions_array) #Trim at this threshold value and calculate error.
		if args.error > error[0]: #If a new max species cut without exceeding what is allowed is reached, save that threshold.
			max_t = threshold
		#if (past == error[0]): #If error wasn't increased, increase the threshold at a higher rate.
		#	threshold = threshold + (threshold_i * 4)
			past[0] = error[0]
		#if (threshold >= .01):
                #        threshold_i = .01
		threshold = threshold + threshold_i
		threshold = round(threshold, n)

	print("\nGreatest result: ")
	sol_new = pfa_loop_control( solution_object, args, error, max_t, done, rate_edge_data, ignition_delay_detailed, conditions_array)
	drgep_trimmed_file = soln2cti.write(sol_new) #Write the solution object with the greatest error that isn't over the allowed ammount.

	return sol_new[1]
Beispiel #3
0
def pfa_loop_control(solution_object, target_species, retained_species, model_file, stored_error, threshold, done, rate_edge_data, ignition_delay_detailed, conditions_array):

    """
    This function handles the reduction, simulation, and comparision for a single threshold value

    Parameters
    ----------

    solution_object: object being reduced # target_species:
    target_species: The target species for reduction
    retained_species: A list of species to be retained even if they should be cut by the algorithm
    model_file: The path to the file where the solution object was generated from
    stored_error: Error from the previous reduction attempt
    threshold: current threshold value
    done: are we done reducing yet? Boolean
    rate_edge_data: the DICs for reduction
    ignition_delay_detailed: ignition delay of detailed model
    conditions_array: array holding information about initial conditions

    Returns
    -------

    Returns the reduced solution object for this threshold and updates error value
    
    """

    # Run detailed mechanism and retain initial conditions
    species_retained = []
    printout = ''
    print('Threshold     Species in Mech      Error')

    # Run DRG and create new reduced solution
    exclusion_list = trim_pfa(
        rate_edge_data, solution_object, threshold, retained_species, done,target_species,model_file) # Find out what to cut from the model
    new_solution_objects = trim(solution_object, exclusion_list, model_file) # Cut the exclusion list from the model.
    species_retained.append(len(new_solution_objects[1].species()))

    # Simulated reduced solution
    new_sim = helper.setup_simulations(conditions_array,new_solution_objects[1]) # Create simulation objects for reduced model for all conditions
    ignition_delay_reduced = helper.simulate(new_sim) # Run simulations and process results

    if (ignition_delay_detailed.all() == 0): # Ensure that ignition occured
        print("Original model did not ignite.  Check initial conditions.")
        exit()

    # Calculate error
    error = (abs(ignition_delay_reduced-ignition_delay_detailed)/ignition_delay_detailed)*100 # Calculate error
    printout += str(threshold) + '                 ' + str(len(new_solution_objects[1].species())) + '              '+  str(round(np.max(error), 2)) +'%' + '\n'
    print(printout)
    stored_error[0] = round(np.max(error), 2)

    # Return new model
    new_solution_objects = new_solution_objects[1]
    return new_solution_objects
Beispiel #4
0
def get_limbo_dic(original_model, reduced_model, limbo, final_error, args,
                  id_detailed, conditions_array):
    dic = {}

    og_excl = [
    ]  #For information on how this is set up, refer to run_sa function.
    keep = []
    og_sn = []
    new_sn = []

    species_objex = reduced_model.species()
    for sp in species_objex:
        new_sn.append(sp.name)

    species_objex = original_model.species()
    for sp in species_objex:
        og_sn.append(sp.name)

    for sp in og_sn:
        if sp in new_sn:
            keep.append(sp)

    for sp in original_model.species():
        if not (sp.name in keep):
            og_excl.append(sp.name)

    for sp in limbo:  #For all species in limbo
        excluded = [sp]
        for p in og_excl:
            excluded.append(p)  #Add that species to the list of exclusion.
        new_sol_obs = trim(original_model, excluded,
                           "sa_trim.cti")  #Remove species from the model.
        new_sol = new_sol_obs[1]

        #simulated reduced solution
        new_sim = helper.setup_simulations(
            conditions_array, new_sol
        )  #Create simulation objects for reduced model for all conditions
        id_new = helper.simulate(new_sim)  #Run simulations and process results
        error = (abs(id_new - id_detailed) / id_detailed) * 100
        error = round(np.max(error), 2)
        print(sp + ": " + str(error))
        error = abs(error - final_error)
        dic[sp] = error  #Add adjusted error to dictionary.
    return dic
Beispiel #5
0
def drg_loop_control(solution_object, target_species, retained_species,
                     model_file, stored_error, threshold, done, rate_edge_data,
                     ignition_delay_detailed, conditions_array):
    """Handles the reduction, simulation, and comparision for a single threshold value.

    Parameters
    ----------
    solution_object:
        object being reduced
    target_species : list of str
        List of target species
    retained_species : list of str
        List of species to always be retained
    model_file : string 
        The path to the file where the solution object was generated from
    stored_error: signleton float
        Error of this reduced model simulation
    threshold : float
        current threshold value
    done : bool
        are we done reducing yet?
    rate_edge_data :
        information for calculating the DICs for reduction
    ignition_delay_detailed :
        ignition delay of detailed model
    conditions_array :
        array holding information about initial conditions

    Returns
    -------
    Reduced solution object for this threshold and updates error value

    """

    species_retained = []
    printout = ''
    print('Threshold     Species in Mech      Error')

    # Run DRG and create new reduced solution
    # Find out what to cut from the model
    exclusion_list = trim_drg(rate_edge_data, solution_object, threshold,
                              retained_species, done, target_species)

    # Cut the exclusion list from the model.
    new_solution_objects = trim(solution_object, exclusion_list, model_file)
    species_retained.append(len(new_solution_objects[1].species()))

    # Simulated reduced solution
    # Create simulation objects for reduced model for all conditions
    new_sim = helper.setup_simulations(conditions_array,
                                       new_solution_objects[1])
    ignition_delay_reduced = helper.simulate(
        new_sim)  # Run simulations and process results

    if ignition_delay_detailed.all() == 0:  # Ensure that ignition occured
        print("Original model did not ignite.  Check initial conditions.")
        exit()

    # Calculate error
    error = (abs(ignition_delay_reduced - ignition_delay_detailed) /
             ignition_delay_detailed) * 100  # Calculate error
    printout += str(threshold) + '                 ' + str(
        len(new_solution_objects[1].species())) + '              ' + str(
            round(np.max(error), 2)) + '%' + '\n'
    print(printout)
    stored_error[0] = round(np.max(error), 2)

    # Return new model.
    new_solution_objects = new_solution_objects[1]
    return new_solution_objects
Beispiel #6
0
def run_drg(solution_object, conditions_file, error_limit, target_species,
            retained_species, model_file, final_error):
    """
    Main function for running DRG reduction.

    Parameters
    ----------
    solution_object : ~cantera.Solution
        A Cantera object of the solution to be reduced.
    conditions_file : str
        Name of file with list of autoignition initial conditions.
    error_limit : float
        Maximum allowable error level for reduced model.
    target_species : list of str
        List of target species
    retained_species : list of str
        List of species to always be retained
    model_file : string 
        The path to the file where the solution object was generated from
    final_error: singleton float
        To hold the error level of simulation

    Returns
    -------

    Writes reduced Cantera file and returns reduced Cantera solution object

    """

    assert target_species, 'Need to specify at least one target species.'

    # Singleton to hold whether any more species can be cut from the simulation.
    done = []
    done.append(False)
    threshold = 0.1  # Starting threshold value
    threshold_increment = 0.1
    num_iterations = 1
    error = [10.0]

    conditions_array = readin_conditions(conditions_file)

    # Turn conditions array into unrun simulation objects for the original solution
    sim_array = helper.setup_simulations(conditions_array, solution_object)
    # Run simulations and process results
    ignition_delay_detailed = helper.simulate(sim_array)
    # Get edge weight calculation data.
    rate_edge_data = get_rates_drg(sim_array, solution_object)

    print("Testing for starting threshold value")
    # Trim the solution at that threshold and find the error.
    drg_loop_control(solution_object, target_species, retained_species,
                     model_file, error, threshold, done, rate_edge_data,
                     ignition_delay_detailed, conditions_array)

    # While the error for trimming with that threshold value is greater than allowed.
    while error[0] != 0:
        # Reduce the starting threshold value and try again.
        threshold /= 10
        threshold_increment /= 10
        num_iterations += 1
        drg_loop_control(solution_object, target_species, retained_species,
                         model_file, error, threshold, done, rate_edge_data,
                         ignition_delay_detailed, conditions_array)
        if error[0] <= 0.02:
            error[0] = 0

    print("Starting with a threshold value of " + str(threshold))
    sol_new = solution_object
    final_error[0] = 0
    done[0] = False

    # Run the simulation until nothing else can be cut.
    while not done[0] and error[0] < error_limit:
        # Trim at this threshold value and calculate error.
        sol_new = drg_loop_control(solution_object, target_species,
                                   retained_species, model_file, error,
                                   threshold, done, rate_edge_data,
                                   ignition_delay_detailed, conditions_array)
        # If a new max species cut without exceeding what is allowed is reached, save that threshold.
        if error_limit > error[0]:
            max_t = threshold
            final_error[0] = error[0]
        # if (final_error[0] == error[0]): #If error wasn't increased, increase the threshold at a higher rate.
        #	threshold = threshold + (threshold_increment * 4)
        # if (threshold >= .01):
        #        threshold_increment = .01
        threshold += threshold_increment
        threshold = round(threshold, num_iterations)

    print("Greatest result: ")
    sol_new = drg_loop_control(solution_object, target_species,
                               retained_species, model_file, error, max_t,
                               done, rate_edge_data, ignition_delay_detailed,
                               conditions_array)

    return sol_new
Beispiel #7
0
def run_sa(original_model, reduced_model, ep_star, final_error, args):
    print(final_error)

    if args.conditions_file:
        conditions_array = readin_conditions(str(args.conditions_file))
    elif not args.conditions_file:
        print("Conditions file not found")
        exit()

    sim_array = helper.setup_simulations(
        conditions_array, original_model
    )  #Turn conditions array into unran simulation objects for the original solution
    id_detailed = helper.simulate(
        sim_array)  #Run simulations and process results

    rate_edge_data = get_rates(
        sim_array, original_model)  #Get edge weight calculation data.
    drgep_coeffs = make_dic_drgep(
        original_model, rate_edge_data,
        args.target)  #Make a dictionary of overall interaction coefficients.
    if (id_detailed.all() == 0):  #Ensure that ignition occured
        print("Original model did not ignite.  Check initial conditions.")
        exit()
    old = reduced_model

    while True:

        og_sn = []  #Original species names
        new_sn = []  #Species names in current reduced model
        keep = []  #Species retained from removals
        og_excl = [
        ]  #Species that will be excluded from the final model (Reduction will be preformed on original model)

        species_objex = old.species()
        for sp in species_objex:
            new_sn.append(sp.name)

        species_objex = original_model.species()
        for sp in species_objex:
            og_sn.append(sp.name)

        for sp in og_sn:
            if sp in new_sn:
                keep.append(sp)

        for sp in original_model.species():
            if not (sp.name in keep):
                og_excl.append(sp.name)

        limbo = create_limbo(old, ep_star, drgep_coeffs,
                             args.keepers)  #Find all the species in limbo.

        if len(limbo) == 0:
            return old

        print("In limbo:")
        print(limbo)

        dic = get_limbo_dic(
            original_model, old, limbo, final_error, args, id_detailed,
            conditions_array
        )  #Calculate error for removing each limbo species.
        rm = dic_lowest(dic)  #Species that should be removed (Lowest error).
        exclude = [rm]

        for sp in og_excl:  #Add to list of species that should be excluded from final model.
            exclude.append(sp)

        print()
        print("attempting to remove " + rm)
        new_sol_obs = trim(
            original_model, exclude,
            "sa_trim.cti")  #Remove exclusion list from original model
        new_sol = new_sol_obs[1]

        #simulated reduced solution
        new_sim = helper.setup_simulations(
            conditions_array, new_sol
        )  #Create simulation objects for reduced model for all conditions
        id_new = helper.simulate(new_sim)  #Run simulations and process results

        error = (abs(id_new - id_detailed) / id_detailed) * 100
        error = round(np.max(error), 2)
        print("Error of: " + str(error))
        print()

        if error > args.error:  #If error is greater than allowed, previous reduced model was final reduction.
            print("Final Solution:")
            print(str(old.n_species) + " Species")
            return old

        else:  #If error is still within allowed limit, loop through again to further reduce.
            old = new_sol
Beispiel #8
0
def run_pfa(solution_object, conditions_file, error_limit, target_species, retained_species, model_file, final_error):

	""""
	This is the MAIN top level function for running PFA

	Parameters
	----------

	solution_object: a Cantera object of the solution to be reduced
	conditions_file: The file holding the initial conditions to simulate
	error_limit: The highest allowed error percentage
	target_species: The target species for reduction
	retained_species: A list of species to be retained even if they should be cut by the algorithm
	model_file: The path to the file where the solution object was generated from
	final_error: To hold the error level of the simulation

	Returns
	-------

	Writes reduced Cantera file and returns reduced Catnera solution object
	
	"""    

	if len(target_species) == 0: # If the target species are not specified, puke and die.
		print("Please specify a target species.")
		exit()
	done = [] # Singleton to hold wether or not any more species can be cut from the simulation.
	done.append(False)
	threshold = .1 # Starting threshold value
	threshold_i = .1
	n = 1
	error = [10.0] # Singleton to hold the error value of the previously ran simulation.

	# Check to make sure that conditions exist
	if conditions_file:
		conditions_array = readin_conditions(str(conditions_file))
	elif not conditions_file:
		print("Conditions file not found")
		exit()

	# Turn conditions array into unran simulation objects for the original solution
	sim_array = helper.setup_simulations(conditions_array,solution_object)
	ignition_delay_detailed = helper.simulate(sim_array) #Run simulations and process results
	rate_edge_data = get_rates_pfa(sim_array, solution_object) #Get edge weight calculation data.

	print("Testing for starting threshold value")
	
	# Trim the solution at that threshold and find the error.
	pfa_loop_control(
		solution_object, target_species, retained_species, model_file, error, threshold, done, rate_edge_data, ignition_delay_detailed, conditions_array)
	while error[0] != 0: # While the error for trimming with that threshold value is greater than allowed.
		threshold = threshold / 10 # Reduce the starting threshold value and try again.
		threshold_i = threshold_i / 10
		n = n + 1
		pfa_loop_control(
			solution_object, target_species, retained_species, model_file, error, threshold, done, rate_edge_data, ignition_delay_detailed, conditions_array)
		if error[0] <= .02:
			error[0] = 0

	print("Starting with a threshold value of " + str(threshold))
	
	sol_new = solution_object
	final_error[0] = 0 # An integer representing the error introduced in the final simulation.
	done[0] = False

	while not done[0] and error[0] < error_limit: # Run the simulation until nothing else can be cut.
		# Trim at this threshold value and calculate error.
		sol_new = pfa_loop_control(
			solution_object, target_species, retained_species, model_file, error, threshold, done, rate_edge_data, ignition_delay_detailed, conditions_array)
		if error_limit >= error[0]: # If a new max species cut without exceeding what is allowed is reached, save that threshold.
			max_t = threshold
		#if (final_error == error[0]): #If error wasn't increased, increase the threshold at a higher rate.
		#	threshold = threshold + (threshold_i * 4)
			final_error[0] = error[0]
		#if (threshold >= .01):
                #        threshold_i = .01
		threshold = threshold + threshold_i
		threshold = round(threshold, n)

	print("\nGreatest result: ")
	sol_new = pfa_loop_control(
		solution_object, target_species, retained_species, model_file, error, max_t, done, rate_edge_data, ignition_delay_detailed, conditions_array)
	
	return sol_new
Beispiel #9
0
def drgep_loop_control(solution_object, target_species, retained_species,
                       model_file, stored_error, threshold, done, max_dic,
                       ignition_delay_detailed, conditions_array):
    """      
    This function handles the reduction, simulation, and comparision for a single threshold value.

    Parameters
    ----------

    solution_object: object being reduced
    target_species: An array of the target species for reduction
    retained_species: An array of species that should not be removed from the model
    model_file: The path to the file holding the original model
    stored_error: past error
    threshold: current threshold value
    done: are we done reducing yet? Boolean
    max_dic: OIC dictionary for DRGEP
    ignition_delay_detailed: ignition delay of detailed model
    conditions_array: array holding information about initial conditions

    Returns
    -------

    Returns the reduced solution object for this threshold and updates error value
   
    """

    # Run detailed mechanism and retain initial conditions
    species_retained = []
    printout = ''
    print('Threshold     Species in Mech      Error')

    # Run DRGEP and create new reduced solution
    exclusion_list = trim_drgep(max_dic, solution_object, threshold,
                                retained_species,
                                done)  # Find out what to cut from the model
    new_solution_objects = trim(
        solution_object, exclusion_list,
        model_file)  # Cut the exclusion list from the model.
    species_retained.append(len(new_solution_objects[1].species()))

    # Simulated reduced solution
    new_sim = helper.setup_simulations(
        conditions_array, new_solution_objects[1]
    )  # Create simulation objects for reduced model for all conditions
    ignition_delay_reduced = helper.simulate(
        new_sim)  # Run simulations and process results

    if ignition_delay_detailed.all() == 0:  # Ensure that ignition occured
        print("Original model did not ignite.  Check initial conditions.")
        exit()

    # Calculate and print error.
    error = (abs(ignition_delay_reduced - ignition_delay_detailed) /
             ignition_delay_detailed) * 100  # Calculate error
    printout += str(threshold) + '                 ' + str(
        len(new_solution_objects[1].species())) + '              ' + str(
            round(np.max(error), 2)) + '%' + '\n'
    print(printout)
    stored_error[0] = round(np.max(error), 2)

    # Return new model
    new_solution_objects = new_solution_objects[1]
    return new_solution_objects
Beispiel #10
0
def get_limbo_dic(original_model, reduced_model, limbo, final_error,
                  id_detailed, conditions_array):
    """
	Creates a dictionary of all of the species in limbo and their errors for sensitivity analysis.

	Parameters
	----------

	original_model: The original version of the model being reduced
	reduced_model: The model produced by the previous reduction
	limbo: A list of the species in limbo
	final_error: Error percentage between the reduced and origanal models
	id_detailed: The ignition delays for each simulation of the original model
	conditions_array: An array holding the initial conditions for simulations
	
	Returns
	-------

	A dictionary with species error to be used for sensitivity anaylsis.

	"""

    dic = {}

    # For information on how this is set up, refer to run_sa function.
    og_excl = []
    keep = []
    og_sn = []
    new_sn = []

    species_objex = reduced_model.species()
    for sp in species_objex:
        new_sn.append(sp.name)

    species_objex = original_model.species()
    for sp in species_objex:
        og_sn.append(sp.name)

    for sp in og_sn:
        if sp in new_sn:
            keep.append(sp)

    for sp in original_model.species():
        if not (sp.name in keep):
            og_excl.append(sp.name)

    for sp in limbo:  # For all species in limbo
        excluded = [sp]
        for p in og_excl:
            excluded.append(p)  # Add that species to the list of exclusion.
        # Remove species from the model.
        new_sol_obs = trim(original_model, excluded, "sa_trim.cti")
        new_sol = new_sol_obs[1]

        # Simulated reduced solution
        new_sim = helper.setup_simulations(
            conditions_array, new_sol
        )  # Create simulation objects for reduced model for all conditions
        id_new = helper.simulate(
            new_sim)  # Run simulations and process results
        error = (abs(id_new - id_detailed) / id_detailed) * 100
        error = round(np.max(error), 2)
        print(sp + ": " + str(error))
        error = abs(error - final_error)
        dic[sp] = error  # Add adjusted error to dictionary.
    return dic
Beispiel #11
0
def run_sa(original_model, reduced_model, ep_star, final_error,
           conditions_file, target, keepers, error_limit):
    """
	Runs a sensitivity analysis on a resulting reduced model.
	
	Parameters
	----------

	original_model: The original version of the model being reduced
	reduced_model: The model produced by the previous reduction
	ep_star: The epsilon star value for the sensitivity analysis
	final_error: Error percentage between the reduced and origanal models
	conditions_file: The file holding the initial conditions for simulations
	target: The target species for the reduction
	keepers: A list of species that should be retained no matter what
	error_limit: The maximum allowed error between the reduced and original models
	
	Returns
	-------

	The model after the sensitivity analysis has been preformed on it.

	"""

    if conditions_file:
        conditions_array = readin_conditions(str(conditions_file))
    elif not conditions_file:
        print("Conditions file not found")
        exit()

    # Turn conditions array into unran simulation objects for the original solution
    sim_array = helper.setup_simulations(conditions_array, original_model)
    id_detailed = helper.simulate(
        sim_array)  # Run simulations and process results

    rate_edge_data = get_rates(
        sim_array, original_model)  # Get edge weight calculation data.

    # Make a dictionary of overall interaction coefficients.
    drgep_coeffs = make_dic_drgep(original_model, rate_edge_data, target)
    if (id_detailed.all() == 0):  # Ensure that ignition occured
        print("Original model did not ignite.  Check initial conditions.")
        exit()
    old = reduced_model

    while True:

        og_sn = []  # Original species names
        new_sn = []  # Species names in current reduced model
        keep = []  # Species retained from removals
        og_excl = [
        ]  # Species that will be excluded from the final model (Reduction will be preformed on original model)

        species_objex = old.species()
        for sp in species_objex:
            new_sn.append(sp.name)

        species_objex = original_model.species()
        for sp in species_objex:
            og_sn.append(sp.name)

        for sp in og_sn:
            if sp in new_sn:
                keep.append(sp)

        for sp in original_model.species():
            if not (sp.name in keep):
                og_excl.append(sp.name)

        # Find all the species in limbo.
        limbo = create_limbo(old, ep_star, drgep_coeffs, keepers)

        if len(limbo) == 0:
            return old

        print("In limbo:")
        print(limbo)

        # Calculate error for removing each limbo species.
        dic = get_limbo_dic(original_model, old, limbo, final_error,
                            id_detailed, conditions_array)
        rm = dic_lowest(dic)  # Species that should be removed (Lowest error).
        exclude = [rm]

        for sp in og_excl:  # Add to list of species that should be excluded from final model.
            exclude.append(sp)

        print()
        print("attempting to remove " + rm)

        # Remove exclusion list from original model
        new_sol_obs = trim(original_model, exclude, "sa_trim.cti")
        new_sol = new_sol_obs[1]

        # Simulated reduced solution
        new_sim = helper.setup_simulations(
            conditions_array, new_sol
        )  # Create simulation objects for reduced model for all conditions
        id_new = helper.simulate(
            new_sim)  # Run simulations and process results

        error = (abs(id_new - id_detailed) / id_detailed) * 100
        error = round(np.max(error), 2)
        print("Error of: " + str(error))
        print()

        # If error is greater than allowed, previous reduced model was final reduction.
        if error > error_limit:
            print("Final Solution:")
            print(str(old.n_species) + " Species")
            return old

        else:  # If error is still within allowed limit, loop through again to further reduce.
            old = new_sol