Generalizes pumping and filtering

So that people can pump and filter gasses without worrying about the
thermodynamics too much.
This commit is contained in:
mwerezak
2014-07-26 15:11:29 -04:00
parent 5f9f6e2054
commit 293855c48e
4 changed files with 120 additions and 124 deletions

View File

@@ -1,3 +1,99 @@
//Generalized gas pumping proc.
//Moves gas from one gas_mixture to another and returns the amount of power needed (assuming 1 second), or -1 if no gas was pumped.
//transfer_moles - Limits the amount of moles to transfer. The actual amount of gas moved may also be limited by available_power, if given.
//available_power - the maximum amount of power that may be used when moving gas. If null then the transfer is not limited by power, however power will still be used!
/obj/machinery/atmospherics/var/last_flow_rate = 0 //Can't return multiple values, unfortunately...
/obj/machinery/atmospherics/proc/pump_gas(var/datum/gas_mixture/source, var/datum/gas_mixture/sink, var/transfer_moles = null, var/available_power = null)
if (source.total_moles < MINUMUM_MOLES_TO_PUMP)
return -1
if (!transfer_moles)
transfer_moles = source.total_moles
//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 (available_power && specific_power > 0)
transfer_moles = min(transfer_moles, available_power / specific_power)
if (transfer_moles < MINUMUM_MOLES_TO_PUMP)
return -1
last_flow_rate = (transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here
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
return -1
var/power_draw = specific_power*transfer_moles
if (power_draw > 0)
removed.add_thermal_energy(power_draw) //1st law - energy is conserved
sink.merge(removed)
return power_draw
//Generalized gas filtering proc.
//Filters the gasses specified by filtering from one gas_mixture to another and returns the amount of power needed (assuming 1 second), or -1 if no gas was filtered.
//filtering - A list of gasids to be filtered from source
//total_transfer_moles - Limits the amount of moles to filter. The actual amount of gas filtered may also be limited by available_power, if given.
//available_power - the maximum amount of power that may be used when filtering gas. If null then the filtering is not limited by power, however power will still be used!
/obj/machinery/atmospherics/proc/filter_gas(var/list/filtering, var/datum/gas_mixture/source, var/datum/gas_mixture/sink, var/total_transfer_moles = null, var/available_power = null)
if (source.total_moles < MINUMUM_MOLES_TO_PUMP)
return -1
filtering &= source.gas //only filter gasses that are actually there.
//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 filtering)
if (source.gas[g] < MINUMUM_MOLES_TO_PUMP)
continue
var/specific_power = calculate_specific_power_gas(g, source, sink)/ATMOS_FILTER_EFFICIENCY
specific_power_gas[g] = specific_power
total_specific_power += specific_power
total_filterable_moles += source.gas[g]
if (total_filterable_moles < MINUMUM_MOLES_TO_PUMP)
return -1
//Figure out how much of each gas to filter
if (!total_transfer_moles)
total_transfer_moles = total_filterable_moles
else
total_transfer_moles = min(total_transfer_moles, total_filterable_moles)
//limit transfer_moles based on available power
if (available_power && total_specific_power > 0)
total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power)
if (total_transfer_moles < MINUMUM_MOLES_TO_PUMP)
return -1
var/power_draw = 0
last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here
for (var/g in filtering)
var/transfer_moles = source.gas[g]
//filter gas in proportion to the mole ratio
transfer_moles = min(transfer_moles, total_transfer_moles*(source.gas[g]/total_filterable_moles))
source.gas[g] -= transfer_moles
sink.gas[g] += transfer_moles //do we need to check if g is in sink.gas first?
power_draw += specific_power_gas[g]*transfer_moles
if (power_draw > 0)
sink.add_thermal_energy(power_draw) //gotta conserve that energy
//Remix the resulting gases
sink.update_values()
source.update_values()
return power_draw
//Calculates the amount of power needed to move one mole from source to sink.
/obj/machinery/atmospherics/proc/calculate_specific_power(datum/gas_mixture/source, datum/gas_mixture/sink)
//Calculate the amount of energy required
@@ -32,5 +128,4 @@
update_use_power(1)
if (usage_amount > idle_power_usage)
use_power(round(usage_amount)) //in practice it's pretty rare that we will get here, so calling use_power() is alright.
use_power(round(usage_amount)) //in practice it's pretty rare that we will get here, so calling use_power() is alright.

View File

@@ -30,7 +30,6 @@ Thus, the two variables affect pump operation are set in New():
active_power_usage = 7500 //This also doubles as a measure of how powerful the pump is, in Watts. 7500 W ~ 10 HP
var/last_power_draw = 0 //for UI
var/last_flow_rate = 0 //for UI
var/max_pressure_setting = 15000 //kPa
var/frequency = 0
@@ -69,7 +68,19 @@ Thus, the two variables affect pump operation are set in New():
var/power_draw = -1
if (air1.temperature > 0 || air2.temperature > 0)
power_draw = pump_gas(air1, air2)
var/pressure_delta = target_pressure - air2.return_pressure()
if(pressure_delta > 0.01)
/* 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)
*/
power_draw = pump_gas(air1, air2, air1.total_moles, active_power_usage)
if(network1)
network1.update = 1
@@ -90,44 +101,6 @@ Thus, the two variables affect pump operation are set in New():
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
/obj/machinery/atmospherics/binary/pump/proc/set_frequency(new_frequency)

View File

@@ -28,7 +28,6 @@
var/pump_direction = 1 //0 = siphoning, 1 = releasing
var/last_power_draw = 0
var/last_flow_rate = 0
var/external_pressure_bound = EXTERNAL_PRESSURE_BOUND
var/internal_pressure_bound = INTERNAL_PRESSURE_BOUND
@@ -158,13 +157,11 @@
if(pressure_checks & PRESSURE_CHECK_INTERNAL)
pressure_delta = min(pressure_delta, air_contents.return_pressure() - internal_pressure_bound) //decreasing the pressure here
//Unfortunately there's no good way to get the volume of the room, so assume 10 tiles
//We will overshoot in small rooms when dealing with huge pressures but it won't be so bad
var/output_volume = environment.volume * environment.group_multiplier
var/air_temperature = environment.temperature? environment.volume : air_contents.temperature
var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION)
power_draw = transfer_gas(air_contents, environment, transfer_moles)
power_draw = pump_gas(air_contents, environment, transfer_moles, active_power_usage)
else //external -> internal
if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
pressure_delta = min(pressure_delta, environment_pressure - external_pressure_bound) //decreasing the pressure here
@@ -172,14 +169,13 @@
pressure_delta = min(pressure_delta, internal_pressure_bound - air_contents.return_pressure()) //increasing the pressure here
var/output_volume = air_contents.volume * air_contents.group_multiplier
var/air_temperature = air_contents.temperature? air_contents.temperature : environment.temperature
var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION)
//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)
power_draw = pump_gas(environment, air_contents, transfer_moles, active_power_usage)
if(network)
network.update = 1

View File

@@ -126,9 +126,15 @@
var/power_draw = -1
if (environment.temperature > 0 || air_contents.temperature > 0)
if(scrubbing)
power_draw = filter_gas(environment)
//limit flow rate from turfs
var/transfer_moles = min(environment.total_moles, environment.total_moles*MAX_FILTER_FLOWRATE/environment.volume) //group_multiplier gets divided out here
power_draw = filter_gas(scrubbing_gas, environment, air_contents, transfer_moles, active_power_usage)
else //Just siphon all air
power_draw = siphon_gas(environment)
//limit flow rate from turfs
var/transfer_moles = min(environment.total_moles, environment.total_moles*MAX_SIPHON_FLOWRATE/environment.volume) //group_multiplier gets divided out here
power_draw = pump_gas(environment, air_contents, transfer_moles, active_power_usage)
if (power_draw < 0)
update_use_power(0)
@@ -144,80 +150,6 @@
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.
update_icon()