Skip to content

Commit

Permalink
Hopefully fix atmos issues (#656)
Browse files Browse the repository at this point in the history
* Check for divide by near zero (#22876)

* Clamp after AdjustMoles() (#22907)

Clamping is needed because x - x can be negative with floating point
numbers. If we don't clamp here, the caller always has to call
GetMoles(), clamp, then SetMoles(), which makes this function not very
useful.

* Add maximum atmos temperature limit (#22882)

* Add Tmax

* Increase Tmax

* Revert "Add YAML gas reactions (#22803)" (#22939)

This reverts commit 054321d.

Co-authored-by: Kevin Zheng <[email protected]>

---------

Co-authored-by: Kevin Zheng <[email protected]>
Co-authored-by: Kara <[email protected]>
  • Loading branch information
3 people authored Jan 7, 2024
1 parent a10c109 commit 6afde59
Show file tree
Hide file tree
Showing 10 changed files with 286 additions and 198 deletions.
7 changes: 3 additions & 4 deletions Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ namespace Content.Server.Atmos.EntitySystems
public sealed partial class AtmosphereSystem
{
[Dependency] private readonly IPrototypeManager _protoMan = default!;
[Dependency] private readonly GenericGasReactionSystem _reaction = default!;

private GasReactionPrototype[] _gasReactions = Array.Empty<GasReactionPrototype>();
private float[] _gasSpecificHeats = new float[Atmospherics.TotalNumberOfGases];
Expand Down Expand Up @@ -123,7 +122,7 @@ public void Merge(GasMixture receiver, GasMixture giver)
var receiverHeatCapacity = GetHeatCapacity(receiver);
var giverHeatCapacity = GetHeatCapacity(giver);
var combinedHeatCapacity = receiverHeatCapacity + giverHeatCapacity;
if (combinedHeatCapacity > 0f)
if (combinedHeatCapacity > Atmospherics.MinimumHeatCapacity)
{
receiver.Temperature = (GetThermalEnergy(giver, giverHeatCapacity) + GetThermalEnergy(receiver, receiverHeatCapacity)) / combinedHeatCapacity;
}
Expand Down Expand Up @@ -167,7 +166,7 @@ public void DivideInto(GasMixture source, List<GasMixture> receivers)
sourceHeatCapacity ??= GetHeatCapacity(source);
var receiverHeatCapacity = GetHeatCapacity(receiver);
var combinedHeatCapacity = receiverHeatCapacity + sourceHeatCapacity.Value * fraction;
if (combinedHeatCapacity > 0f)
if (combinedHeatCapacity > Atmospherics.MinimumHeatCapacity)
receiver.Temperature = (GetThermalEnergy(source, sourceHeatCapacity.Value * fraction) + GetThermalEnergy(receiver, receiverHeatCapacity)) / combinedHeatCapacity;
}
}
Expand Down Expand Up @@ -347,7 +346,7 @@ public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder)
break;
}

return _reaction.ReactAll(GasReactions, mixture, holder);
return reaction;
}

public enum GasCompareResult
Expand Down
130 changes: 0 additions & 130 deletions Content.Server/Atmos/EntitySystems/GenericGasReactionSystem.cs

This file was deleted.

13 changes: 6 additions & 7 deletions Content.Server/Atmos/GasMixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Content.Server.Atmos.Reactions;
using Content.Shared.Atmos;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;

namespace Content.Server.Atmos
{
Expand Down Expand Up @@ -58,8 +59,9 @@ public float Temperature
get => _temperature;
set
{
DebugTools.Assert(!float.IsNaN(_temperature));
if (Immutable) return;
_temperature = MathF.Max(value, Atmospherics.TCMB);
_temperature = MathF.Min(MathF.Max(value, Atmospherics.TCMB), Atmospherics.Tmax);
}
}

Expand Down Expand Up @@ -120,12 +122,9 @@ public void AdjustMoles(int gasId, float quantity)
if (!float.IsFinite(quantity))
throw new ArgumentException($"Invalid quantity \"{quantity}\" specified!", nameof(quantity));

Moles[gasId] += quantity;

var moles = Moles[gasId];

if (!float.IsFinite(moles) || float.IsNegative(moles))
throw new Exception($"Invalid mole quantity \"{moles}\" in gas Id {gasId} after adjusting moles with \"{quantity}\"!");
// Clamping is needed because x - x can be negative with floating point numbers. If we don't
// clamp here, the caller always has to call GetMoles(), clamp, then SetMoles().
Moles[gasId] = MathF.Max(Moles[gasId] + quantity, 0);
}
}

Expand Down
33 changes: 33 additions & 0 deletions Content.Server/Atmos/Reactions/AmmoniaOxygenReaction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Content.Server.Atmos.EntitySystems;
using Content.Shared.Atmos;
using JetBrains.Annotations;

namespace Content.Server.Atmos.Reactions;

[UsedImplicitly]
public sealed partial class AmmoniaOxygenReaction : IGasReactionEffect
{
public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale)
{
var nAmmonia = mixture.GetMoles(Gas.Ammonia);
var nOxygen = mixture.GetMoles(Gas.Oxygen);
var nTotal = mixture.TotalMoles;

// Concentration-dependent reaction rate
var fAmmonia = nAmmonia/nTotal;
var fOxygen = nOxygen/nTotal;
var rate = MathF.Pow(fAmmonia, 2) * MathF.Pow(fOxygen, 2);

var deltaMoles = nAmmonia / Atmospherics.AmmoniaOxygenReactionRate * 2 * rate;

if (deltaMoles <= 0 || nAmmonia - deltaMoles < 0)
return ReactionResult.NoReaction;

mixture.AdjustMoles(Gas.Ammonia, -deltaMoles);
mixture.AdjustMoles(Gas.Oxygen, -deltaMoles);
mixture.AdjustMoles(Gas.NitrousOxide, deltaMoles / 2);
mixture.AdjustMoles(Gas.WaterVapor, deltaMoles * 1.5f);

return ReactionResult.Reacting;
}
}
58 changes: 58 additions & 0 deletions Content.Server/Atmos/Reactions/FrezonCoolantReaction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using Content.Server.Atmos.EntitySystems;
using Content.Shared.Atmos;
using JetBrains.Annotations;

namespace Content.Server.Atmos.Reactions;

/// <summary>
/// Takes in nitrogen and frezon and cools down the surrounding area.
/// </summary>
[UsedImplicitly]
public sealed partial class FrezonCoolantReaction : IGasReactionEffect
{
public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale)
{
var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true);
var temperature = mixture.Temperature;

var energyModifier = 1f;
var scale = (temperature - Atmospherics.FrezonCoolLowerTemperature) /
(Atmospherics.FrezonCoolMidTemperature - Atmospherics.FrezonCoolLowerTemperature);

if (scale > 1f)
{
// Scale energy but not frezon usage if we're in a very, very hot place
energyModifier = Math.Min(scale, Atmospherics.FrezonCoolMaximumEnergyModifier);
scale = 1f;
}

if (scale <= 0)
return ReactionResult.NoReaction;

var initialNit = mixture.GetMoles(Gas.Nitrogen);
var initialFrezon = mixture.GetMoles(Gas.Frezon);

var burnRate = initialFrezon * scale / Atmospherics.FrezonCoolRateModifier;

var energyReleased = 0f;
if (burnRate > Atmospherics.MinimumHeatCapacity)
{
var nitAmt = Math.Min(burnRate * Atmospherics.FrezonNitrogenCoolRatio, initialNit);
var frezonAmt = Math.Min(burnRate, initialFrezon);
mixture.AdjustMoles(Gas.Nitrogen, -nitAmt);
mixture.AdjustMoles(Gas.Frezon, -frezonAmt);
mixture.AdjustMoles(Gas.NitrousOxide, nitAmt + frezonAmt);
energyReleased = burnRate * Atmospherics.FrezonCoolEnergyReleased * energyModifier;
}

energyReleased /= heatScale; // adjust energy to make sure speedup doesn't cause mega temperature rise
if (energyReleased >= 0f)
return ReactionResult.NoReaction;

var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture, true);
if (newHeatCapacity > Atmospherics.MinimumHeatCapacity)
mixture.Temperature = (temperature * oldHeatCapacity + energyReleased) / newHeatCapacity;

return ReactionResult.Reacting;
}
}
35 changes: 1 addition & 34 deletions Content.Server/Atmos/Reactions/GasReactionPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ public sealed partial class GasReactionPrototype : IPrototype
public string ID { get; private set; } = default!;

/// <summary>
/// Minimum gas amount requirements. Reactions that meet these minimum mole requirements
/// have their reaction effects run. Generic gas reactions do not have minimum requirements.
/// Minimum gas amount requirements.
/// </summary>
[DataField("minimumRequirements")]
public float[] MinimumRequirements { get; private set; } = new float[Atmospherics.TotalNumberOfGases];
Expand All @@ -43,13 +42,6 @@ public sealed partial class GasReactionPrototype : IPrototype
[DataField("minimumTemperature")]
public float MinimumTemperatureRequirement { get; private set; } = Atmospherics.TCMB;

/// <summary>
/// If this is a generic gas reaction, multiply the initial rate by this. The default is reasonable for
/// synthesis reactions. Consider raising this for fires.
/// </summary>
[DataField("rateMultiplier")]
public float RateMultiplier = 1f;

/// <summary>
/// Minimum energy requirement.
/// </summary>
Expand All @@ -68,31 +60,6 @@ public sealed partial class GasReactionPrototype : IPrototype
/// </summary>
[DataField("effects")] private List<IGasReactionEffect> _effects = new();

/// <summary>
/// Energy released by the reaction.
/// </summary>
[DataField("enthalpy")]
public float Enthalpy;

/// <summary>
/// Integer gas IDs and integer ratios required in the reaction. If this is defined, the
/// generic gas reaction will run.
/// </summary>
[DataField("reactants")]
public Dictionary<Gas, int> Reactants = new();

/// <summary>
/// Integer gas IDs and integer ratios of reaction products.
/// </summary>
[DataField("products")]
public Dictionary<Gas, int> Products = new();

/// <summary>
/// Integer gas IDs and how much they modify the activation energy (J/mol).
/// </summary>
[DataField("catalysts")]
public Dictionary<Gas, int> Catalysts = new();

/// <summary>
/// Process all reaction effects.
/// </summary>
Expand Down
28 changes: 28 additions & 0 deletions Content.Server/Atmos/Reactions/N2ODecompositionReaction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Content.Server.Atmos.EntitySystems;
using Content.Shared.Atmos;
using JetBrains.Annotations;

namespace Content.Server.Atmos.Reactions;

/// <summary>
/// Decomposes Nitrous Oxide into Nitrogen and Oxygen.
/// </summary>
[UsedImplicitly]
public sealed partial class N2ODecompositionReaction : IGasReactionEffect
{
public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, AtmosphereSystem atmosphereSystem, float heatScale)
{
var cacheN2O = mixture.GetMoles(Gas.NitrousOxide);

var burnedFuel = cacheN2O / Atmospherics.N2ODecompositionRate;

if (burnedFuel <= 0 || cacheN2O - burnedFuel < 0)
return ReactionResult.NoReaction;

mixture.AdjustMoles(Gas.NitrousOxide, -burnedFuel);
mixture.AdjustMoles(Gas.Nitrogen, burnedFuel);
mixture.AdjustMoles(Gas.Oxygen, burnedFuel / 2);

return ReactionResult.Reacting;
}
}
Loading

0 comments on commit 6afde59

Please sign in to comment.