Corrects the amount of work done by the turbine when compressing gas (#30838)

* put in new compression cost formula

* Update turbine.dm

* Update turbine.dm

* apply compression costs before removing the gas from the tile so we use the correct pressure

* Reduces intake amount of there isn't sufficient energy in the compressor
This commit is contained in:
Migratingcocofruit
2025-11-12 12:53:00 +00:00
committed by GitHub
parent 876bae072d
commit 06f35678f6
+43 -5
View File
@@ -351,20 +351,58 @@
return
// By how much we compress the gas going into the turbine
compressor.compression_ratio = 1 + (COMPRESSION_RATIO_MAX - 1) * (compressor.rpm /(compressor.rpm + COMPRESSION_RPM_CURVE))
compressor.compression_ratio = 1 + (COMPRESSION_RATIO_MAX - 1) * (compressor.rpm / (compressor.rpm + COMPRESSION_RPM_CURVE))
// How much of the gas in the input tile we suck in
var/input_fraction = compressor.compression_ratio * compressor.throttle / 50
var/datum/gas_mixture/environment = get_turf_air(compressor.inturf)
var/datum/gas_mixture/output_side = get_turf_air(get_step(compressor.turbine.loc, compressor.turbine.loc.dir))
// Volume of our input in cubic meteres
var/input_volume = 2.5 * input_fraction
// Pressure of the turf we suck in gas from in Pa
var/pascal_pressure = environment.return_pressure() * 1000
// Do work to compress the input gas
// The equation we use is for the work done by a piston, which should give us the same result as what a turbine would do due to conservation of energy and our gasses being ideal:
// W(x) = P1 * V1 * (ln(L1) - ln(L1 - x)) = P1 * V1 * (ln(L1 / (L1 - x))).
// Where P1 [Pa] is the starting pressure, V1 [m^3] is the volume of the tile we suck in, L1 [m] is the length of the cylinder and x [m] is the length of the piston's movement. We also have S[m^2], which is cylinder's cross section area
// If we instead write L1 as V1 / S and (L1 - x) as V2 / S, V2 being our final volume, we get ln(L1 / (L1 - x)) = ln((V1 / S) /(V2 / S)) = ln(V1 / V2). For a final volume of 0.05 cubic meteres we get ln(V1 * 20).
// We also multiply by 1000 since we get pressure in kilopascals rather than pascals.
var/compression_energy_cost = max(0, pascal_pressure * input_volume * (log(input_volume * 20)))
// If we don't have enough energy to draw in as much gas as we should reduce the amount of gas going in
// Ideally we would use the inverse of the work function, but I couldn't find an expression for it. Instead we're approximating with binary search.
if(compression_energy_cost > compressor.kinetic_energy)
// We always take in at least 50 litres of gas since that would mean no compression at all and no work done.
var/bottom = 0.02
var/top = input_fraction
// We should never even come close to this, but better safe than sorry
var/iterations = 100
// 5% without going over is a good enough approximation
while(iterations > 0 && (compression_energy_cost > compressor.kinetic_energy || (compression_energy_cost < compressor.kinetic_energy * 0.95 && compressor.kinetic_energy - compression_energy_cost > 1)))
iterations--
input_fraction = (top + bottom) / 2
input_volume = 2.5 * input_fraction
compression_energy_cost = max(0, pascal_pressure * input_volume * (log(input_volume * 20)))
if(compression_energy_cost > compressor.kinetic_energy)
top = input_fraction
else
bottom = input_fraction
// We changed how much gas we sucked in so we need to change the compression ratio. this is just the input volume divided by final volume(0.05 m^3)
compressor.compression_ratio = input_volume * 20
// Make the compressor do the work
compressor.kinetic_energy -= compression_energy_cost
// The more we are able to compress the gas the more gas we can shove in the compressor
var/transfer_moles = environment.total_moles() * (compressor.compression_ratio / 50) * compressor.throttle
var/transfer_moles = environment.total_moles() * input_fraction
var/datum/gas_mixture/removed = environment.remove(transfer_moles)
compressor.gas_contained.merge(removed)
// Record how much gas we took in for the UI
compressor.gas_throughput = compressor.gas_contained.total_moles()
// Lose kinetic energy to compressing the gas.
compressor.kinetic_energy -= min(compressor.kinetic_energy, compressor.compression_ratio * (compressor.gas_contained.return_pressure() - environment.return_pressure()))
var/gas_heat_capacity = compressor.gas_contained.heat_capacity()
var/total_heat_energy = compressor.gas_contained.thermal_energy() + (compressor.temperature * compressor.heat_capacity)