Pressure Relief Valve (#36708)
* initial system (this math is probably WRONG) * General code cleanup and OnExamined support (holy moly this code sucks) * UICode and related events foundation TODO: - Actually write the XAML UI and the underlying system - Un-shitcode the entire thing - Actually test everything... * Working UI code TODO: Make predicted, as this certainly isn't predicted. Even though I said it was. It isn't. * Remove one TODO for unshitcoding the examine code * Add reminder yea * Make predicted (defenitely isn't) (also defenitely isn't a copypaste from pressure pump code) * It's predicted! TODO: - Give it snazzy predicted visuals! - Have a different field for pressure entry, lest it gets bulldozed every UI update. * Improve gas pressure relief valve UI TODO: Reminder to reduce amount of dirties using deltafields * Implement DirtyField prediction * Entity<T> cleanup A lot of Entity<T> conversions and lukewarm cleanup. Also got caught copy pasting code in 4K UHD but it's not like you couldn't tell. * More cleanup and comments * Remove TODO comment on bulldozing window title * """refactoring""" - Move appearance out of shared and finally fix it. Pointless to predict appearance in this instance. - More Entity<T> conversions because I like them. - Move UI creation handling over entirely to the ActivatableUI system. - Fix a hardcoded locale string (why????). * Add visuals * Revert debugging variable replacememt yea * Revert skissue * Remove unused using directives and remove TODO * Localize, cleanup, document * Fix adminlogging discrepancy * Add ability to construct, add guidebook entry * Clear up comment * Add guidebook tooltip to valve * Convert GasPressureReliefValveBoundUserInterface declaration into primary constructor * Adds more input handling and adds autofill on open * Un-deepfry input validator shitcode Genuinely what was I smoking * improve visuals logic * Refactor again - Update math to the correct implementation - Moved code that could be re-used in the future into a helper method under AtmosphereSystem.Gases.cs * I'm sorry but I hate warnings * Remove unused using directive in AtmosphereSystem.Gases.cs * Review and cleanup * Lukewarm UI glossup * Maintainer for the upstream project btw * Remove redundant state sets and messy logic * Unduplicate valve updater code * Redo UI (im sorry Slarti) * run tests * Test refactored UI messaging * Second round of UI improvements - God please find a way to improve this system. Feels bad. * Update loop implementation * Further predict UI * Clear up SetToCurrentThreshold * cleanup * Update to master + pipe layers and bug fixes want to run tests * fixes * Deploy rename pipebomb * Documentation and requested changes * Rename the method that wiggled away * Undo rounding changes * Fix comment * Rename and cleanup * Apply suggestions from code review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
This commit is contained in:
@@ -252,6 +252,128 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
Merge(destination, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the dimensionless fraction of gas required to equalize pressure between two gas mixtures.
|
||||
/// </summary>
|
||||
/// <param name="gasMixture1">The first gas mixture involved in the pressure equalization.
|
||||
/// This mixture should be the one you always expect to be the highest pressure.</param>
|
||||
/// <param name="gasMixture2">The second gas mixture involved in the pressure equalization.</param>
|
||||
/// <returns>A float (from 0 to 1) representing the dimensionless fraction of gas that needs to be transferred from the
|
||||
/// mixture of higher pressure to the mixture of lower pressure.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This properly takes into account the effect
|
||||
/// of gas merging from inlet to outlet affecting the temperature
|
||||
/// (and possibly increasing the pressure) in the outlet.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The gas is assumed to expand freely,
|
||||
/// so the temperature of the gas with the greater pressure is not changing.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// If you want to calculate the moles required to equalize pressure between an inlet and an outlet,
|
||||
/// multiply the fraction returned by the source moles.
|
||||
/// </example>
|
||||
public float FractionToEqualizePressure(GasMixture gasMixture1, GasMixture gasMixture2)
|
||||
{
|
||||
/*
|
||||
Problem: the gas being merged from the inlet to the outlet could affect the
|
||||
temp. of the gas and cause a pressure rise.
|
||||
We want the pressure to be equalized, so we have to account for this.
|
||||
|
||||
For clarity, let's assume that gasMixture1 is the inlet and gasMixture2 is the outlet.
|
||||
|
||||
We require mechanical equilibrium, so \( P_1' = P_2' \)
|
||||
|
||||
Before the transfer, we have:
|
||||
\( P_1 = \frac{n_1 R T_1}{V_1} \)
|
||||
\( P_2 = \frac{n_2 R T_2}{V_2} \)
|
||||
|
||||
After removing fraction \( x \) moles from the inlet, we have:
|
||||
\( P_1' = \frac{(1 - x) n_1 R T_1}{V_1} \)
|
||||
|
||||
The outlet will gain the same \( x n_1 \) moles of gas.
|
||||
So \( n_2' = n_2 + x n_1 \)
|
||||
|
||||
After mixing, the outlet temperature will be changed.
|
||||
Denote the new mixture temperature as \( T_2' \).
|
||||
Volume is constant.
|
||||
So we have:
|
||||
\( P_2' = \frac{(n_2 + x n_1) R T_2}{V_2} \)
|
||||
|
||||
The total energy of the incoming inlet to outlet gas at \( T_1 \) plus the existing energy of the outlet gas at \( T_2 \)
|
||||
will be equal to the energy of the new outlet gas at \( T_2' \).
|
||||
This leads to the following derivation:
|
||||
\( x n_1 C_1 T_1 + n_2 C_2 T_2 = (x n_1 C_1 + n_2 C_2) T_2' \)
|
||||
|
||||
Where \( C_1 \) and \( C_2 \) are the heat capacities of the inlet and outlet gases, respectively.
|
||||
|
||||
Solving for \( T_2' \) gives us:
|
||||
\( T_2' = \frac{x n_1 C_1 T_1 + n_2 C_2 T_2}{x n_1 C_1 + n_2 C_2} \)
|
||||
|
||||
Once again, we require mechanical equilibrium (\( P_1' = P_2' \)),
|
||||
so we can substitute \( T_2' \) into the pressure equation:
|
||||
|
||||
\( \frac{(1 - x) n_1 R T_1}{V_1} =
|
||||
\frac{(n_2 + x n_1) R}{V_2} \cdot
|
||||
\frac{x n_1 C_1 T_1 + n_2 C_2 T_2}
|
||||
{x n_1 C_1 + n_2 C_2} \)
|
||||
|
||||
Now it's a matter of solving for \( x \).
|
||||
Not going to show the full derivation here, just steps.
|
||||
1. Cancel common factor \( R \).
|
||||
2. Multiply both sides by \( x n_1 C_1 + n_2 C_2 \), so that everything
|
||||
becomes a polynomial in terms of \( x \).
|
||||
3. Expand both sides.
|
||||
4. Collect like powers of \( x \).
|
||||
5. After collecting, you should end up with a polynomial of the form:
|
||||
|
||||
\( (-n_1 C_1 T_1 (1 + \frac{V_2}{V_1})) x^2 +
|
||||
(n_1 T_1 \frac{V_2}{V_1} (C_1 - C_2) - n_2 C_1 T_1 - n_1 C_2 T_2) x +
|
||||
(n_1 T_1 \frac{V_2}{V_1} C_2 - n_2 C_2 T_2) = 0 \)
|
||||
|
||||
Divide through by \( n_1 C_1 T_1 \) and replace each ratio with a symbol for clarity:
|
||||
\( k_V = \frac{V_2}{V_1} \)
|
||||
\( k_n = \frac{n_2}{n_1} \)
|
||||
\( k_T = \frac{T_2}{T_1} \)
|
||||
\( k_C = \frac{C_2}{C_1} \)
|
||||
*/
|
||||
|
||||
// Ensure that P_1 > P_2 so the quadratic works out.
|
||||
if (gasMixture1.Pressure < gasMixture2.Pressure)
|
||||
{
|
||||
(gasMixture1, gasMixture2) = (gasMixture2, gasMixture1);
|
||||
}
|
||||
|
||||
// Establish the dimensionless ratios.
|
||||
var volumeRatio = gasMixture2.Volume / gasMixture1.Volume;
|
||||
var molesRatio = gasMixture2.TotalMoles / gasMixture1.TotalMoles;
|
||||
var temperatureRatio = gasMixture2.Temperature / gasMixture1.Temperature;
|
||||
var heatCapacityRatio = GetHeatCapacity(gasMixture2) / GetHeatCapacity(gasMixture1);
|
||||
|
||||
// The quadratic equation is solved for the transfer fraction.
|
||||
var quadraticA = 1 + volumeRatio;
|
||||
var quadraticB = molesRatio - volumeRatio + heatCapacityRatio * (temperatureRatio + volumeRatio);
|
||||
var quadraticC = heatCapacityRatio * (molesRatio * temperatureRatio - volumeRatio);
|
||||
|
||||
return (-quadraticB + MathF.Sqrt(quadraticB * quadraticB - 4 * quadraticA * quadraticC)) / (2 * quadraticA);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the number of moles that need to be removed from a <see cref="GasMixture"/> to reach a target pressure threshold.
|
||||
/// </summary>
|
||||
/// <param name="gasMixture">The gas mixture whose moles and properties will be used in the calculation.</param>
|
||||
/// <param name="targetPressure">The target pressure threshold to calculate against.</param>
|
||||
/// <returns>The difference in moles required to reach the target pressure threshold.</returns>
|
||||
/// <remarks>The temperature of the gas is assumed to be not changing due to a free expansion.</remarks>
|
||||
public static float MolesToPressureThreshold(GasMixture gasMixture, float targetPressure)
|
||||
{
|
||||
// Kid named PV = nRT.
|
||||
return gasMixture.TotalMoles -
|
||||
targetPressure * gasMixture.Volume / (Atmospherics.R * gasMixture.Temperature);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a gas mixture is probably safe.
|
||||
/// This only checks temperature and pressure, not gas composition.
|
||||
|
||||
Reference in New Issue
Block a user