Add radiators (#18728)

* Add radiators

* Limit heat transfer to fluid heat capacity

* Adjust datafield names

* Fix material arbitrage

* This code has been debugged, and so there are no more bugs. Debugging code is therefore unnecessary

* Adjust radiator layer subfloor visibility

* Cache CVars

* No default

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>

* Like and unsubscribe

* Fix CVar caching

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
This commit is contained in:
Kevin Zheng 2023-08-06 01:21:05 -07:00 committed by GitHub
parent d13de403dd
commit db5dee6db3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 250 additions and 0 deletions

View File

@ -0,0 +1,36 @@
namespace Content.Server.Atmos.Components;
[RegisterComponent]
public sealed class HeatExchangerComponent : Component
{
[ViewVariables(VVAccess.ReadWrite)]
[DataField("inlet")]
public string InletName { get; set; } = "inlet";
[ViewVariables(VVAccess.ReadWrite)]
[DataField("outlet")]
public string OutletName { get; set; } = "outlet";
/// <summary>
/// Pipe conductivity (mols/kPa/sec).
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("conductivity")]
public float G { get; set; } = 1f;
/// <summary>
/// Thermal convection coefficient (J/degK/sec).
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("convectionCoefficient")]
public float K { get; set; } = 8000f;
/// <summary>
/// Thermal radiation coefficient. Number of "effective" tiles this
/// radiator radiates compared to superconductivity tile losses.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("radiationCoefficient")]
public float alpha { get; set; } = 400f;
}

View File

@ -78,6 +78,16 @@ namespace Content.Server.Atmos.EntitySystems
return mixture.Temperature * cachedHeatCapacity;
}
/// <summary>
/// Add 'dQ' Joules of energy into 'mixture'.
/// </summary>
public void AddHeat(GasMixture mixture, float dQ)
{
var c = GetHeatCapacity(mixture);
float dT = dQ / c;
mixture.Temperature += dT;
}
/// <summary>
/// Merges the <see cref="giver"/> gas mixture into the <see cref="receiver"/> gas mixture.
/// The <see cref="giver"/> gas mixture is not modified by this method.

View File

@ -0,0 +1,97 @@
using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Piping.Components;
using Content.Server.Atmos.Piping.Unary.Components;
using Content.Server.Atmos;
using Content.Server.Atmos.Components;
using Content.Server.NodeContainer.EntitySystems;
using Content.Server.NodeContainer.Nodes;
using Content.Server.NodeContainer;
using Content.Shared.Atmos.Piping;
using Content.Shared.Atmos;
using Content.Shared.CCVar;
using Content.Shared.Interaction;
using JetBrains.Annotations;
using Robust.Shared.Configuration;
using Robust.Shared.Timing;
namespace Content.Server.Atmos.EntitySystems;
public sealed class HeatExchangerSystem : EntitySystem
{
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
float tileLoss;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<HeatExchangerComponent, AtmosDeviceUpdateEvent>(OnAtmosUpdate);
// Getting CVars is expensive, don't do it every tick
_cfg.OnValueChanged(CCVars.SuperconductionTileLoss, CacheTileLoss, true);
}
public override void Shutdown()
{
base.Shutdown();
_cfg.UnsubValueChanged(CCVars.SuperconductionTileLoss, CacheTileLoss);
}
private void CacheTileLoss(float val)
{
tileLoss = val;
}
private void OnAtmosUpdate(EntityUid uid, HeatExchangerComponent comp, AtmosDeviceUpdateEvent args)
{
if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
|| !_nodeContainer.TryGetNode(nodeContainer, comp.InletName, out PipeNode? inlet)
|| !_nodeContainer.TryGetNode(nodeContainer, comp.OutletName, out PipeNode? outlet))
{
return;
}
// Positive dN flows from inlet to outlet
var dt = 1/_atmosphereSystem.AtmosTickRate;
var dP = inlet.Air.Pressure - outlet.Air.Pressure;
var dN = comp.G*dP*dt;
GasMixture xfer;
if (dN > 0)
xfer = inlet.Air.Remove(dN);
else
xfer = outlet.Air.Remove(-dN);
var radTemp = Atmospherics.TCMB;
// Convection
var environment = _atmosphereSystem.GetContainingMixture(uid, true, true);
if (environment != null)
{
radTemp = environment.Temperature;
// Positive dT is from pipe to surroundings
var dT = xfer.Temperature - environment.Temperature;
var dE = comp.K * dT * dt;
var envLim = Math.Abs(_atmosphereSystem.GetHeatCapacity(environment) * dT * dt);
var xferLim = Math.Abs(_atmosphereSystem.GetHeatCapacity(xfer) * dT * dt);
var dEactual = Math.Sign(dE) * Math.Min(Math.Abs(dE), Math.Min(envLim, xferLim));
_atmosphereSystem.AddHeat(xfer, -dEactual);
_atmosphereSystem.AddHeat(environment, dEactual);
}
// Radiation
float dTR = xfer.Temperature - radTemp;
float a0 = tileLoss / MathF.Pow(Atmospherics.T20C, 4);
float dER = comp.alpha * a0 * MathF.Pow(dTR, 4) * dt;
_atmosphereSystem.AddHeat(xfer, -dER);
if (dN > 0)
_atmosphereSystem.Merge(outlet.Air, xfer);
else
_atmosphereSystem.Merge(inlet.Air, xfer);
}
}

View File

@ -937,6 +937,12 @@ namespace Content.Shared.CCVar
public static readonly CVarDef<bool> Superconduction =
CVarDef.Create("atmos.superconduction", false, CVar.SERVERONLY);
/// <summary>
/// Heat loss per tile due to radiation at 20 degC, in W.
/// </summary>
public static readonly CVarDef<float> SuperconductionTileLoss =
CVarDef.Create("atmos.superconduction_tile_loss", 30f, CVar.SERVERONLY);
/// <summary>
/// Whether excited groups will be processed and created.
/// </summary>

View File

@ -379,3 +379,45 @@
acts: ["Destruction"]
- type: Machine
board: GasRecyclerMachineCircuitboard
- type: entity
parent: GasBinaryBase
id: HeatExchanger
name: radiator
description: Transfers heat between the pipe and its surroundings.
placement:
mode: SnapgridCenter
components:
- type: Rotatable
- type: Transform
noRot: false
- type: Sprite
sprite: Structures/Piping/Atmospherics/heatexchanger.rsi
layers:
- sprite: Structures/Piping/Atmospherics/pipe.rsi
state: pipeStraight
map: [ "enum.PipeVisualLayers.Pipe" ]
- state: heStraight
map: [ "enum.SubfloorLayers.FirstLayer" ]
- type: SubFloorHide
visibleLayers:
- enum.SubfloorLayers.FirstLayer
- type: Appearance
- type: PipeColorVisuals
- type: AtmosDevice
- type: HeatExchanger
- type: NodeContainer
nodes:
inlet:
!type:PipeNode
nodeGroupID: Pipe
pipeDirection: North
outlet:
!type:PipeNode
nodeGroupID: Pipe
pipeDirection: South
- type: Construction
graph: GasBinary
node: radiator
- type: StaticPrice
price: 50

View File

@ -46,6 +46,12 @@
amount: 2
doAfter: 1
- to: radiator
steps:
- material: Steel
amount: 8
doAfter: 1
- node: pressurepump
entity: GasPressurePump
edges:
@ -159,3 +165,21 @@
doAfter: 1
- tool: Welding
doAfter: 1
- node: radiator
entity: HeatExchanger
edges:
- to: start
conditions:
- !type:EntityAnchored
anchored: false
completed:
- !type:SpawnPrototype
prototype: SheetSteel1
amount: 8
- !type:DeleteEntity
steps:
- tool: Screwing
doAfter: 1
- tool: Welding
doAfter: 1

View File

@ -663,6 +663,22 @@
conditions:
- !type:TileNotBlocked {}
- type: construction
id: HeatExchanger
name: radiator
description: Transfers heat between the pipe and its surroundings.
graph: GasBinary
startNode: start
targetNode: radiator
category: construction-category-utilities
placementMode: SnapgridCenter
canBuildInImpassable: false
icon:
sprite: Structures/Piping/Atmospherics/heatexchanger.rsi
state: heStraight
conditions:
- !type:TileNotBlocked {}
# ATMOS TRINARY
- type: construction
id: GasFilter

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 929 B

View File

@ -0,0 +1,19 @@
{
"version":1,
"size":{
"x":32,
"y":32
},
"license":"CC-BY-SA-3.0",
"copyright":"Taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da and modified by BasedUser",
"states":[
{
"name":"heStraight",
"directions":4
},
{
"name":"heBend",
"directions":4
}
]
}