Cleanup, adds setup parameters for atmos machinery

Allows atmos machinery efficiency to be adjusted in setup.dm
Limits flow rates when moving gas from a turf to avoid very high pressures being created when they shouldn't be.
Attempts to limit processing when there isn't much gas to be moved, for performance.
Reverts all changes to _gas_mixture.dm
This commit is contained in:
mwerezak
2014-07-26 13:08:02 -04:00
parent 11c9f3bb9b
commit 3f6c1ff622
5 changed files with 184 additions and 190 deletions

View File

@@ -67,58 +67,67 @@ Thus, the two variables affect pump operation are set in New():
last_flow_rate = 0 last_flow_rate = 0
return return
var/datum/gas_mixture/source = air1 var/power_draw = -1
var/datum/gas_mixture/sink = air2 if (air1.temperature > 0 || air2.temperature > 0)
power_draw = pump_gas(air1, air2)
var/pressure_delta = target_pressure - sink.return_pressure()
//Calculate necessary moles to transfer using PV=nRT
if(pressure_delta > 0.01 && (source.total_moles > 0) && (source.temperature > 0 || sink.temperature > 0))
var/transfer_moles = source.total_moles
/* TODO Uncomment this once we have a good way to get the volume of a pipe network.
//Figure out how much gas to transfer to meet the target pressure.
var/air_temperature = (sink.temperature > 0)? sink.temperature : source.temperature
var/output_volume = sink.volume * sink.group_multiplier
//Return the number of moles that would have to be transfered to bring sink to the target pressure
var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION)
*/
//Calculate the amount of energy required and limit transfer_moles based on available power
var/specific_power = calculate_specific_power(source, sink) //this has to be calculated before we modify any gas mixtures
if (specific_power > 0)
transfer_moles = min(transfer_moles, active_power_usage / specific_power)
var/power_draw = specific_power*transfer_moles
var/datum/gas_mixture/removed = source.remove(transfer_moles)
last_flow_rate = (removed.total_moles/(removed.total_moles + source.total_moles))*source.volume
if (power_draw > 0)
removed.add_thermal_energy(power_draw) //1st law - energy is conserved
handle_pump_power_draw(power_draw)
last_power_draw = power_draw
else
handle_pump_power_draw(idle_power_usage)
last_power_draw = idle_power_usage
sink.merge(removed)
if(network1) if(network1)
network1.update = 1 network1.update = 1
if(network2) if(network2)
network2.update = 1 network2.update = 1
else
if (power_draw < 0)
update_use_power(0) update_use_power(0)
last_power_draw = 0 last_power_draw = 0
last_flow_rate = 0 last_flow_rate = 0
return 1 else if (power_draw > 0)
handle_pump_power_draw(power_draw)
last_power_draw = power_draw
else
handle_pump_power_draw(idle_power_usage)
last_power_draw = idle_power_usage
return 1 return 1
//pumps gas from source to sink, and returns the power used, or -1 if no pumping was done
/obj/machinery/atmospherics/binary/pump/proc/pump_gas(var/datum/gas_mixture/source, var/datum/gas_mixture/sink)
var/pressure_delta = target_pressure - sink.return_pressure()
if(pressure_delta < 0.01 || source.total_moles < MINUMUM_MOLES_TO_PUMP)
return -1
var/transfer_moles = source.total_moles
/* TODO Uncomment this once we have a good way to get the volume of a pipe network.
//Figure out how much gas to transfer to meet the target pressure.
var/air_temperature = (sink.temperature > 0)? sink.temperature : source.temperature
var/output_volume = sink.volume * sink.group_multiplier
//Return the number of moles that would have to be transfered to bring sink to the target pressure
var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION)
*/
//Calculate the amount of energy required and limit transfer_moles based on available power
var/specific_power = calculate_specific_power(source, sink)/ATMOS_PUMP_EFFICIENCY //this has to be calculated before we modify any gas mixtures
if (specific_power > 0)
transfer_moles = min(transfer_moles, active_power_usage / specific_power)
if (transfer_moles < MINUMUM_MOLES_TO_PUMP)
return -1
var/power_draw = specific_power*transfer_moles
var/datum/gas_mixture/removed = source.remove(transfer_moles)
last_flow_rate = (removed.total_moles/(removed.total_moles + source.total_moles))*source.volume
if (power_draw > 0)
removed.add_thermal_energy(power_draw) //1st law - energy is conserved
sink.merge(removed)
return power_draw
//Radio remote control //Radio remote control
/obj/machinery/atmospherics/binary/pump/proc/set_frequency(new_frequency) /obj/machinery/atmospherics/binary/pump/proc/set_frequency(new_frequency)

View File

@@ -144,16 +144,14 @@
last_power_draw = 0 last_power_draw = 0
last_flow_rate = 0 last_flow_rate = 0
return 0 return 0
var/datum/gas_mixture/environment = loc.return_air() var/datum/gas_mixture/environment = loc.return_air()
var/environment_pressure = environment.return_pressure() var/environment_pressure = environment.return_pressure()
if(air_contents.temperature == 0 && environment.temperature == 0)
return 0
var/pressure_delta = DEFAULT_PRESSURE_DELTA var/pressure_delta = DEFAULT_PRESSURE_DELTA
if(pressure_delta > 0.5) var/power_draw = -1
if((air_contents.temperature > 0 || environment.temperature > 0) && pressure_delta > 0.5)
if(pump_direction) //internal -> external if(pump_direction) //internal -> external
if(pressure_checks & PRESSURE_CHECK_EXTERNAL) if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
pressure_delta = min(pressure_delta, external_pressure_bound - environment_pressure) //increasing the pressure here pressure_delta = min(pressure_delta, external_pressure_bound - environment_pressure) //increasing the pressure here
@@ -166,7 +164,7 @@
var/air_temperature = environment.temperature? environment.volume : air_contents.temperature var/air_temperature = environment.temperature? environment.volume : air_contents.temperature
var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION) var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION)
transfer_gas(air_contents, environment, transfer_moles) power_draw = transfer_gas(air_contents, environment, transfer_moles)
else //external -> internal else //external -> internal
if(pressure_checks & PRESSURE_CHECK_EXTERNAL) if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
pressure_delta = min(pressure_delta, environment_pressure - external_pressure_bound) //decreasing the pressure here pressure_delta = min(pressure_delta, environment_pressure - external_pressure_bound) //decreasing the pressure here
@@ -178,46 +176,57 @@
var/air_temperature = air_contents.temperature? air_contents.temperature : environment.temperature var/air_temperature = air_contents.temperature? air_contents.temperature : environment.temperature
var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION) var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION)
transfer_gas(environment, air_contents, transfer_moles) //limit flow rate from turfs
transfer_moles = min(transfer_moles, environment.total_moles*MAX_SIPHON_FLOWRATE/environment.volume) //group_multiplier gets divided out here
power_draw = transfer_gas(environment, air_contents, transfer_moles)
if(network) if(network)
network.update = 1 network.update = 1
else
if (power_draw < 0)
last_power_draw = 0 last_power_draw = 0
last_flow_rate = 0 last_flow_rate = 0
update_use_power(0) update_use_power(0)
if (power_draw > 0)
handle_pump_power_draw(power_draw)
last_power_draw = power_draw
else
handle_pump_power_draw(idle_power_usage)
last_power_draw = idle_power_usage
return 1 return 1
//pumps gas from source to sink and returns the power used, or -1 if no pumping was done.
/obj/machinery/atmospherics/unary/vent_pump/proc/transfer_gas(datum/gas_mixture/source, datum/gas_mixture/sink, var/transfer_moles) /obj/machinery/atmospherics/unary/vent_pump/proc/transfer_gas(datum/gas_mixture/source, datum/gas_mixture/sink, var/transfer_moles)
if(source.total_moles == 0) if(source.total_moles < MINUMUM_MOLES_TO_PUMP)
update_use_power(0) return -1
return
//limit transfer_moles by available power //limit transfer_moles by available power
var/specific_power = calculate_specific_power(source, sink) //this has to be calculated before we modify any gas mixtures var/specific_power = calculate_specific_power(source, sink)/ATMOS_PUMP_EFFICIENCY //this has to be calculated before we modify any gas mixtures
if (specific_power > 0) if (specific_power > 0)
transfer_moles = min(transfer_moles, active_power_usage / specific_power) transfer_moles = min(transfer_moles, active_power_usage / specific_power)
//Get the gas to be transferred //Get the gas to be transferred
if (transfer_moles < MINUMUM_MOLES_TO_PUMP)
return -1 //don't bother
var/datum/gas_mixture/removed = source.remove(transfer_moles) var/datum/gas_mixture/removed = source.remove(transfer_moles)
if (isnull(removed)) //not sure why this would happen, but it does at the very beginning of the game if (isnull(removed)) //not sure why this would happen, but it does at the very beginning of the game
return return -1
last_flow_rate = (removed.total_moles/(removed.total_moles + source.total_moles))*source.volume last_flow_rate = (removed.total_moles/(removed.total_moles + source.total_moles))*source.volume
var/power_draw = specific_power*transfer_moles var/power_draw = specific_power*transfer_moles
if (power_draw > 0) if (power_draw > 0)
removed.add_thermal_energy(power_draw) removed.add_thermal_energy(power_draw)
handle_pump_power_draw(power_draw)
last_power_draw = power_draw
else
handle_pump_power_draw(idle_power_usage)
last_power_draw = idle_power_usage
//merge the removed gas into the sink //merge the removed gas into the sink
sink.merge(removed) sink.merge(removed)
return power_draw
//Radio remote control //Radio remote control

View File

@@ -122,66 +122,17 @@
return 0 return 0
var/datum/gas_mixture/environment = loc.return_air() var/datum/gas_mixture/environment = loc.return_air()
if ((environment.total_moles == 0) || (environment.temperature == 0 && air_contents.temperature == 0))
var/power_draw = -1
if (environment.temperature > 0 || air_contents.temperature > 0)
if(scrubbing)
power_draw = filter_gas(environment)
else //Just siphon all air
power_draw = siphon_gas(environment)
if (power_draw < 0)
update_use_power(0) update_use_power(0)
return else if (power_draw > 0)
var/power_draw
if(scrubbing)
//Filter it
var/total_specific_power = 0 //the power required to remove one mole of filterable gas
var/total_filterable_moles = 0
var/list/specific_power_gas = list()
for (var/g in scrubbing_gas)
if (environment.gas[g] < 0.1)
continue //don't bother
var/specific_power = calculate_specific_power_gas(g, environment, air_contents)
specific_power_gas[g] = specific_power
total_specific_power += specific_power
total_filterable_moles += environment.gas[g]
if (total_filterable_moles == 0)
update_use_power(0)
return
//Calculate the amount of energy required and limit transfer_moles based on available power
power_draw = 0
var/total_transfer_moles = total_filterable_moles
if (total_specific_power > 0)
total_transfer_moles = min(total_transfer_moles, active_power_usage/total_specific_power)
for (var/g in scrubbing_gas)
var/transfer_moles = environment.gas[g]
if (specific_power_gas[g] > 0)
//if our flow rate is limited by available power, the proportion of the filtered gas is based on mole ratio
transfer_moles = min(transfer_moles, total_transfer_moles*(environment.gas[g]/total_filterable_moles))
environment.gas[g] -= transfer_moles
air_contents.gas[g] += transfer_moles
power_draw += specific_power_gas[g]*transfer_moles
//Remix the resulting gases
air_contents.update_values()
environment.update_values()
else //Just siphon all air
var/transfer_moles = environment.total_moles
//Calculate the amount of energy required
var/specific_power = calculate_specific_power(environment, air_contents) //this has to be calculated before we modify any gas mixtures
if (specific_power > 0)
transfer_moles = min(transfer_moles, active_power_usage / specific_power)
if (transfer_moles < 0.01)
update_use_power(0)
return //don't bother
power_draw = specific_power*transfer_moles
air_contents.merge(environment.remove(transfer_moles))
if (power_draw > 0)
air_contents.add_thermal_energy(power_draw)
//last_power_draw = power_draw //last_power_draw = power_draw
handle_pump_power_draw(power_draw) handle_pump_power_draw(power_draw)
else else
@@ -193,6 +144,80 @@
return 1 return 1
//filters gas from environment and returns the amount of power used, or -1 if no filtering was done
/obj/machinery/atmospherics/unary/vent_scrubber/proc/filter_gas(datum/gas_mixture/environment)
//Filter it
var/total_specific_power = 0 //the power required to remove one mole of filterable gas
var/total_filterable_moles = 0
var/list/specific_power_gas = list()
for (var/g in scrubbing_gas)
if (environment.gas[g] < MINUMUM_MOLES_TO_PUMP)
continue //don't bother
var/specific_power = calculate_specific_power_gas(g, environment, air_contents)/ATMOS_FILTER_EFFICIENCY
specific_power_gas[g] = specific_power
total_specific_power += specific_power
total_filterable_moles += environment.gas[g]
if (total_filterable_moles < MINUMUM_MOLES_TO_PUMP)
return -1
//Figure out how much of each gas to filter
var/total_transfer_moles = total_filterable_moles
//limit flow rate from turfs
total_transfer_moles = min(total_transfer_moles, environment.total_moles*MAX_FILTER_FLOWRATE/environment.volume) //group_multiplier gets divided out here
//limit transfer_moles based on available power
var/power_draw = 0
if (total_specific_power > 0)
total_transfer_moles = min(total_transfer_moles, active_power_usage/total_specific_power)
for (var/g in scrubbing_gas)
var/transfer_moles = environment.gas[g]
if (specific_power_gas[g] > 0)
//if our flow rate is being limited by available power, the proportion of the filtered gas is based on mole ratio
transfer_moles = min(transfer_moles, total_transfer_moles*(environment.gas[g]/total_filterable_moles))
environment.gas[g] -= transfer_moles
air_contents.gas[g] += transfer_moles
power_draw += specific_power_gas[g]*transfer_moles
if (power_draw > 0)
air_contents.add_thermal_energy(power_draw)
//Remix the resulting gases
air_contents.update_values()
environment.update_values()
return power_draw
//siphons gas from environment and returns the power used, or -1 if no siphoning was done
/obj/machinery/atmospherics/unary/vent_scrubber/proc/siphon_gas(datum/gas_mixture/environment)
if (environment.total_moles < MINUMUM_MOLES_TO_PUMP)
return -1 //no point doing all this processing when source is a vacuum
var/transfer_moles = environment.total_moles
//limit flow rate from turfs
transfer_moles = min(transfer_moles, environment.total_moles*MAX_SIPHON_FLOWRATE/environment.volume) //group_multiplier gets divided out here
//Calculate the amount of energy required and limit transfer_moles based on available power
var/specific_power = calculate_specific_power(environment, air_contents)/ATMOS_PUMP_EFFICIENCY //this has to be calculated before we modify any gas mixtures
if (specific_power > 0)
transfer_moles = min(transfer_moles, active_power_usage / specific_power)
if (transfer_moles < MINUMUM_MOLES_TO_PUMP)
return -1 //don't bother
var/power_draw = specific_power*transfer_moles
var/datum/gas_mixture/removed = environment.remove(transfer_moles)
if (power_draw > 0)
removed.add_thermal_energy(power_draw)
air_contents.merge(removed)
return power_draw
/obj/machinery/atmospherics/unary/vent_scrubber/hide(var/i) //to make the little pipe section invisible, the icon changes. /obj/machinery/atmospherics/unary/vent_scrubber/hide(var/i) //to make the little pipe section invisible, the icon changes.
update_icon() update_icon()

View File

@@ -4,24 +4,16 @@ What are the archived variables for?
This prevents race conditions that arise based on the order of tile processing. This prevents race conditions that arise based on the order of tile processing.
*/ */
#define SPECIFIC_HEAT_TOXIN 200 // J/(mol*K) #define SPECIFIC_HEAT_TOXIN 200
#define SPECIFIC_HEAT_AIR 20 // J/(mol*K) #define SPECIFIC_HEAT_AIR 20
#define SPECIFIC_HEAT_CDO 30 // J/(mol*K) #define SPECIFIC_HEAT_CDO 30
#define HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,phoron) \ #define HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,phoron) \
max(0, carbon_dioxide * SPECIFIC_HEAT_CDO + (oxygen + nitrogen) * SPECIFIC_HEAT_AIR + phoron * SPECIFIC_HEAT_TOXIN) max(0, carbon_dioxide * SPECIFIC_HEAT_CDO + (oxygen + nitrogen) * SPECIFIC_HEAT_AIR + phoron * SPECIFIC_HEAT_TOXIN)
//we should really have a datum for each gas instead of a bunch of constants
#define MOL_MASS_O2 0.032 // kg/mol
#define MOL_MASS_N2 0.028 // kg/mol
#define MOL_MASS_CDO 0.044 // kg/mol
#define MOL_MASS_PHORON 0.289 // kg/mol
#define MINIMUM_HEAT_CAPACITY 0.0003 #define MINIMUM_HEAT_CAPACITY 0.0003
#define QUANTIZE(variable) (round(variable,0.0001)) #define QUANTIZE(variable) (round(variable,0.0001))
#define TRANSFER_FRACTION 5 //What fraction (1/#) of the air difference to try and transfer #define TRANSFER_FRACTION 5 //What fraction (1/#) of the air difference to try and transfer
#define SPECIFIC_ENTROPY_VACUUM 1500 //technically vacuum doesn't have a specific entropy. Just use a really big number here to show that it's easy to add gas to vacuum and hard to take gas out.
/hook/startup/proc/createGasOverlays() /hook/startup/proc/createGasOverlays()
plmaster = new /obj/effect/overlay() plmaster = new /obj/effect/overlay()
plmaster.icon = 'icons/effects/tile_effects.dmi' plmaster.icon = 'icons/effects/tile_effects.dmi'
@@ -36,11 +28,11 @@ What are the archived variables for?
slmaster.mouse_opacity = 0 slmaster.mouse_opacity = 0
return 1 return 1
/datum/gas/sleeping_agent/specific_heat = 40 //These are used for the "Trace Gases" stuff, but is buggy. //J/(mol*K) /datum/gas/sleeping_agent/specific_heat = 40 //These are used for the "Trace Gases" stuff, but is buggy.
/datum/gas/oxygen_agent_b/specific_heat = 300 //J/(mol*K) /datum/gas/oxygen_agent_b/specific_heat = 300
/datum/gas/volatile_fuel/specific_heat = 30 //J/(mol*K) /datum/gas/volatile_fuel/specific_heat = 30
/datum/gas /datum/gas
var/moles = 0 var/moles = 0
@@ -149,65 +141,6 @@ What are the archived variables for?
return max(MINIMUM_HEAT_CAPACITY,heat_capacity_archived) return max(MINIMUM_HEAT_CAPACITY,heat_capacity_archived)
/datum/gas_mixture/proc/add_thermal_energy(var/thermal_energy)
//Purpose: Adjusting temperature based on thermal energy transfer
//Called by: Anyone who wants to add or remove energy from the gas mix
//Inputs: An amount of energy in J to be added. Negative values remove energy.
//Outputs: The actual thermal energy change. Only relevant if you are removing energy.
var/old_temperature = temperature
var/heat_capacity = heat_capacity()
temperature += thermal_energy/heat_capacity
if (temperature < TCMB)
temperature = TCMB
return (temperature - old_temperature)*heat_capacity
/datum/gas_mixture/proc/get_thermal_energy_change(var/new_temperature)
//Purpose: Determining how much thermal energy is required
//Called by: Anyone. Machines that want to adjust the temperature of a gas mix.
//Inputs: None
//Outputs: The amount of energy required to get to the new temperature in J. A negative value means that energy needs to be removed.
return heat_capacity()*(new_temperature - temperature)
//This is so overkill for spessmen it's hilarious.
//While this proc will return an accurate measure of the entropy, it's much easier to use the specific_entropy_change() proc.
/datum/gas_mixture/proc/specific_entropy()
//Purpose: Returning the specific entropy of the gas mix, i.e. the entropy gained or lost per mole of gas added or removed.
//Called by: Anyone who wants to know how much energy it takes to move gases around in a steady state process (e.g. gas pumps)
//Inputs: None
//Outputs: Specific Entropy.
//Jut assume everything is an ideal gas, so we can use the Ideal Gas Sackur-Tetrode equation.
//After we convert to moles and Liters and extract all those crazy constants inside the ln() we end up with:
//S = R * moles * ( ln[ constant * volume / moles * (molecular_mass * internal_energy / moles)^(3/2) ] + 5/2 )
//Where constant is IDEAL_GAS_ENTROPY_CONSTANT defined in setup.dm
//We need to do this calculation for each type of gas in the mix and add them all up, to properly capture the entropy of mixing.
//It would be nice if each gas type was a datum, then we could just iterate through a list
//the number of moles inside the square root gets divided out
var/sp_entropy_oxygen = ( log( IDEAL_GAS_ENTROPY_CONSTANT * volume / (oxygen + 0.001) * sqrt( ( MOL_MASS_O2 * SPECIFIC_HEAT_AIR * (temperature + 1) ) ** 3 ) + 1) + 5/2 )
var/sp_entropy_nitrogen = ( log( IDEAL_GAS_ENTROPY_CONSTANT * volume / (nitrogen + 0.001) * sqrt( ( MOL_MASS_N2 * SPECIFIC_HEAT_AIR * (temperature + 1) ) ** 3 ) + 1 ) + 5/2 )
var/sp_entropy_carbon_dioxide = ( log( IDEAL_GAS_ENTROPY_CONSTANT * volume / (carbon_dioxide + 0.001) * sqrt( ( MOL_MASS_CDO * SPECIFIC_HEAT_CDO * (temperature + 1) + 1 ) ** 3 ) ) + 5/2 )
var/sp_entropy_phoron = ( log( IDEAL_GAS_ENTROPY_CONSTANT * volume / (phoron + 0.001) * sqrt( ( MOL_MASS_PHORON * SPECIFIC_HEAT_TOXIN * (temperature + 1) ) ** 3 ) + 1 ) + 5/2 )
if (total_moles > 0)
var/oxygen_ratio = oxygen/total_moles
var/nitrogen_ratio = nitrogen/total_moles
var/carbon_dioxide_ratio = carbon_dioxide/total_moles
var/phoron_ratio = phoron/total_moles
return R_IDEAL_GAS_EQUATION * ( oxygen_ratio*sp_entropy_oxygen + nitrogen_ratio*sp_entropy_nitrogen + carbon_dioxide_ratio*sp_entropy_carbon_dioxide + phoron_ratio*sp_entropy_phoron )
return SPECIFIC_ENTROPY_VACUUM
/datum/gas_mixture/proc/total_moles() /datum/gas_mixture/proc/total_moles()
return total_moles return total_moles
/*var/moles = oxygen + carbon_dioxide + nitrogen + phoron /*var/moles = oxygen + carbon_dioxide + nitrogen + phoron

View File

@@ -823,3 +823,21 @@ var/list/RESTRICTED_CAMERA_NETWORKS = list( //Those networks can only be accesse
#define IS_UNATHI 4 #define IS_UNATHI 4
#define MAX_GEAR_COST 5 //Used in chargen for loadout limit. #define MAX_GEAR_COST 5 //Used in chargen for loadout limit.
/*
Atmos Machinery
*/
//These limit the flow rate when taking gas away from turfs. This is necessary because moving 2500 L in a single iteration causes a huge amount of error with pressure and gas calculations.
//This error is related to the fact that we do everything in 1 second steps instead of continuous time. Limiting the flow rate will prevent pressures from overshooting too much.
#define MAX_SIPHON_FLOWRATE 500 //L/s
#define MAX_FILTER_FLOWRATE 200 //L/s
//These control how easy or hard it is to create huge pressure gradients with pumps and filters. Lower values means it takes longer to create large pressures differences.
//If you want to limit the ability of players to create very high pressures then it makes more sense to adjust these instead of artificially limiting the pump settings.
//Has no effect on pumping gasses from high pressure to low, only from low to high. Must be between 0 and 1.
#define ATMOS_PUMP_EFFICIENCY 1.0
#define ATMOS_FILTER_EFFICIENCY 0.9
#define MINUMUM_MOLES_TO_PUMP 0.01 //will not bother pumping or filtering if the gas source as fewer than this amount of moles, to help with performance.