diff --git a/code/ATMOSPHERICS/atmospherics_helpers.dm b/code/ATMOSPHERICS/atmospherics_helpers.dm index 6c1ec58100..0e39a60ae3 100644 --- a/code/ATMOSPHERICS/atmospherics_helpers.dm +++ b/code/ATMOSPHERICS/atmospherics_helpers.dm @@ -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. \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/binary_devices/pump.dm b/code/ATMOSPHERICS/components/binary_devices/pump.dm index 6534729fc5..dd13de5c61 100644 --- a/code/ATMOSPHERICS/components/binary_devices/pump.dm +++ b/code/ATMOSPHERICS/components/binary_devices/pump.dm @@ -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) diff --git a/code/ATMOSPHERICS/components/unary/vent_pump.dm b/code/ATMOSPHERICS/components/unary/vent_pump.dm index eee3eef0da..3d8483ff26 100644 --- a/code/ATMOSPHERICS/components/unary/vent_pump.dm +++ b/code/ATMOSPHERICS/components/unary/vent_pump.dm @@ -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 diff --git a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm index 99dd0286b6..ab60d83998 100644 --- a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm +++ b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm @@ -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()