-
Notifications
You must be signed in to change notification settings - Fork 3
/
ModuleRealActiveRadiator.cs
371 lines (335 loc) · 16.6 KB
/
ModuleRealActiveRadiator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using KSP;
using KSP.Localization;
using Radiators;
namespace RealActiveRadiator
{
public class ModuleRealActiveRadiator : ModuleActiveRadiator
{
[KSPField()]
public FloatCurve cryoCoolerEfficiency;
[KSPField]
public double maxCryoEnergyTransfer = 500.0;
[KSPField]
public double maxCryoElectricCost = 10;
[KSPField]
public double cryoEnergyTransferScale = 1;
[KSPField]
protected bool cooledByOtherRadiators = false;
//[KSPField]
//protected double coolTemperatureThreshold = 297.6;
protected static string cacheAutoLOC_232071;
protected static string cacheAutoLOC_232067;
protected static string cacheAutoLOC_232036;
[KSPField(guiName = "AR:RefrCost", guiActive = false)]
public string D_RefrCost = "???";
protected int electricResourceIndex = -1;
protected int ECID = -1;
protected double baseElectricRate = 0;
protected double refrigerationThrottle = 1;
protected BaseField Dfld_RefrCost;
protected List<Part> compensatedParts = new List<Part> ();
public ModuleRealActiveRadiator () : base()
{
}
internal static void CacheLocalStrings()
{
ModuleRealActiveRadiator.cacheAutoLOC_232036 = Localizer.Format("#autoLOC_232036");
ModuleRealActiveRadiator.cacheAutoLOC_232067 = Localizer.Format("#autoLOC_232067");
ModuleRealActiveRadiator.cacheAutoLOC_232071 = Localizer.Format("#autoLOC_232071");
}
public override void OnAwake()
{
base.OnAwake();
electricResourceIndex = this.resHandler.inputResources.FindIndex(x => x.name == "ElectricCharge");
if (electricResourceIndex >= 0)
{
baseElectricRate = this.resHandler.inputResources[electricResourceIndex].rate;
ECID = this.resHandler.inputResources[electricResourceIndex].id;
}
if (cryoCoolerEfficiency == null)
cryoCoolerEfficiency = new FloatCurve();
if (cryoCoolerEfficiency.Curve.keys.Length == 0)
cryoCoolerEfficiency.Add(0f, 0.7f);
}
public override void OnStart(StartState state)
{
base.OnStart (state);
this.Dfld_RefrCost = base.Fields ["D_RefrCost"];
}
public new void FixedUpdate()
{
base.FixedUpdate();
if (this.Dfld_RefrCost != null)
this.Dfld_RefrCost.guiActive = PhysicsGlobals.ThermalDataDisplay;
}
public override string GetInfo()
{
StringBuilder stringBuilder = new StringBuilder();
if (this.resHandler.inputResources.Count > 0)
{
stringBuilder.Append(this.resHandler.PrintModuleResources(1.0));
}
stringBuilder.Append("\n<b><color=#99ff00ff>" + ModuleRealActiveRadiator.cacheAutoLOC_232036 + "</color></b>\n");
double num = this.maxEnergyTransfer;
stringBuilder.AppendFormat(Localizer.Format("#autoLOC_232038", new object[] {
num
}), new object[0]);
double num2 = 0.0;
int count = base.part.DragCubes.Cubes.Count;
while (count-- > 0)
{
DragCube dragCube = base.part.DragCubes.Cubes[count];
double num3 = (double)(dragCube.Area[0] + dragCube.Area[1] + dragCube.Area[2] + dragCube.Area[3] + dragCube.Area[4] + dragCube.Area[5]);
if (num3 > num2)
{
num2 = num3;
}
}
if (num2 != 0.0)
{
double num4 = base.part.skinMaxTemp * base.part.radiatorHeadroom;
num4 *= num4;
num4 *= num4;
stringBuilder.Append(Localizer.Format("#autoLOC_232057", new string[] {
(num2 * base.part.emissiveConstant * num4 * PhysicsGlobals.StefanBoltzmanConstant * 0.001).ToString ("F0")
}));
}
StringBuilder stringBuilder2 = new StringBuilder();
stringBuilder2.AppendFormat("{0:0.00}", this.energyTransferScale * 100.0);
stringBuilder.Append(Localizer.Format("#autoLOC_232060", new string[] {
stringBuilder2.ToString ()
}));
{
stringBuilder.Append(ModuleRealActiveRadiator.cacheAutoLOC_232067);
}
if (this.parentCoolingOnly)
{
stringBuilder.Append(ModuleRealActiveRadiator.cacheAutoLOC_232071);
}
if (maxCryoElectricCost > 0)
{
stringBuilder.Append("\n<b><color=#99ff00ff>Max Cryogenic Cooling</color></b>\n");
stringBuilder.Append(" <b><color=#00C3FFff>@20K = " + (CoolingEfficiency(20, 300) * maxCryoElectricCost).ToString("F2") + "kW" + "</color>\n");
stringBuilder.Append(" <b><color=#00C3FFff>@90K = " + (CoolingEfficiency(90, 300) * maxCryoElectricCost).ToString("F2") + "kW" + "</color>\n");
}
else
{
stringBuilder.Append("No cryogenic cooling capacity.\n");
}
return stringBuilder.ToString();
}
protected override void CheckPartCaches()
{
if (!this.partCachesDirty)
{
return;
}
this.activeRadiatorParts.Clear();
this.nonRadiatorParts.Clear();
this.compensatedParts.Clear();
int count = base.vessel.parts.Count;
ModuleActiveRadiator radPart;
while (count-- > 0)
{
Part part = base.vessel.parts[count];
if (radPart = part.FindModuleImplementing<ModuleActiveRadiator>())
{
// There can be other mods that inherit from ModuleActiveRadiator type.
// Need to ensure that the found part is actually a RealActiveRadiator.
if (radPart is ModuleRealActiveRadiator && !((ModuleRealActiveRadiator)radPart).cooledByOtherRadiators)
this.activeRadiatorParts.Add(part);
}
else
{
this.nonRadiatorParts.Add(part);
if (part.Modules.Contains("ModuleFuelTanks"))
{
this.compensatedParts.Add(part);
}
}
}
this.partCachesDirty = false;
}
//<summary>
// Returns the cooling efficiency taking into account both Carnot and efficiency % of Carnot of the cooler.
// This ONLY is valid for conditions where refrigeration is happening. Otherwise stock radiator conditions apply.
//</summary>
public double CoolingEfficiency(double coolingTemp, double hotTemp)
{
return Math.Max(coolingTemp / (hotTemp - coolingTemp) * cryoCoolerEfficiency.Evaluate((float)coolingTemp), 0);
}
protected override void InternalCooling(RadiatorData thisRadiator, int radCount)
{
if (!base.vessel.IsFirstFrame())
{
// TODO hard coding this for ElectricCharge but I may do something like this for all resource inputs IF there are likely to be other resource inputs
// and IF those other inputs are likely to need scaling...
double coolingEfficiency = 1;
double refrigerationCost = 0;
if (this.Dfld_RadCount.guiActive)
{
this.D_RadCount = radCount.ToString();
}
this.coolParts.Clear();
this.hotParts.Clear();
int count = this.nonRadiatorParts.Count;
while (count-- > 0)
{
Part part = this.nonRadiatorParts[count];
if (part.temperature > part.maxTemp * part.radiatorMax)
{
this.hotParts.Add(part);
}
}
int count2 = this.hotParts.Count;
for (int i = 0; i < count2; i++)
{
Part part2 = this.hotParts[i];
bool flag = true;
if (this.parentCoolingOnly)
{
flag = this.IsSibling(part2);
}
if (flag)
{
RadiatorData thermalData = RadiatorUtilities.GetThermalData(part2);
double energyDifference = thermalData.Energy - thermalData.MaxEnergy;
if (energyDifference > 0.0)
{
this.coolParts.Add(thermalData);
}
}
}
int cooledParts = this.coolParts.Count;
// Would have liked to do this part as coolParts was being built so the list doesn't have to be walked through twice
// but I don't know the amount of flux until after it's done being built - so if I want to throttle refrigeration I have to do this.
for (int i = 0; i < cooledParts; i++)
{
if (coolParts[i].Part.temperature < base.part.temperature)
{
RadiatorData partThermalData = this.coolParts[i];
coolingEfficiency = CoolingEfficiency(coolParts[i].Part.temperature, base.part.temperature);
double _maxCryoEnergyTransfer = maxCryoElectricCost * coolingEfficiency;
double excessHeat = (partThermalData.Energy - partThermalData.MaxEnergy);
excessHeat /= (double)(radCount + cooledParts);
double val = Math.Min(Math.Max(0, thisRadiator.EnergyCap - thisRadiator.Energy), _maxCryoEnergyTransfer);
double liftedHeatFlux = Math.Min(val, excessHeat) * Math.Min(1.0, cryoEnergyTransferScale) * refrigerationThrottle;
refrigerationCost += Math.Min(maxCryoElectricCost, liftedHeatFlux / coolingEfficiency);
}
}
for (int i = 0; i < this.compensatedParts.Count; i++)
{
Part part = compensatedParts[i];
if (!(part.temperature < part.maxTemp * part.radiatorMax))
{
double conductionFlux = part.thermalConductionFlux + part.skinToInternalFlux;
if (conductionFlux > 0 && part.temperature < base.part.temperature)
{
coolingEfficiency = CoolingEfficiency(part.temperature, base.part.temperature);
conductionFlux = Math.Min(conductionFlux, maxCryoElectricCost * coolingEfficiency);
conductionFlux *= refrigerationThrottle;
refrigerationCost += conductionFlux / coolingEfficiency;
}
}
}
if (electricResourceIndex >= 0)
{
this.resHandler.inputResources[electricResourceIndex].rate = baseElectricRate + refrigerationCost;
//double powerAvailability = this.resHandler.UpdateModuleResourceInputs(ref this.status, radCount, 0.9, false, false, true);
double ECAmount, ECMaxAmount;
this.part.GetConnectedResourceTotals(ECID, PartResourceLibrary.GetDefaultFlowMode(ECID), out ECAmount, out ECMaxAmount, true);
// if the craft has mixed radiator types then availability calculation may be wrong
double powerAvailability = ECAmount / ((refrigerationCost * radCount) + 0.1);
if (powerAvailability < 1.0)
{
// Looks like radiator count can include inactive radiators so this could throttle cooling down more than intended.
refrigerationThrottle = powerAvailability * 0.75 / radCount;
refrigerationCost *= refrigerationThrottle;
this.resHandler.inputResources[electricResourceIndex].rate = baseElectricRate + (refrigerationCost);
}
else if (refrigerationThrottle < 1.0)
{
// Try to increase the throttle if power reserves have increased to more than 10x what would be required.
if (powerAvailability >= 10 * refrigerationCost)
{
refrigerationThrottle += 0.001;
refrigerationCost *= refrigerationThrottle;
this.resHandler.inputResources[electricResourceIndex].rate = baseElectricRate + (refrigerationCost);
}
}
//this.resHandler.UpdateModuleResourceInputs(ref this.status, 1, 0.9, false, false, true);
refrigerationThrottle = Math.Min(refrigerationThrottle, 1);
if (this.Dfld_RefrCost.guiActive)
this.D_RefrCost = refrigerationCost.ToString("F4") + " (throttle = " + refrigerationThrottle.ToString("P0") + ")";
}
if (this.Dfld_CoolParts.guiActive)
{
this.D_CoolParts = StringBuilderCache.Format("{0}/{1}", new object[]
{
cooledParts,
this.hotParts.Count
});
}
for (int j = 0; j < cooledParts; j++)
{
RadiatorData radiatorData = this.coolParts[j];
bool useHeatPump = radiatorData.Part.temperature < base.part.temperature;
coolingEfficiency = CoolingEfficiency(coolParts[j].Part.temperature, base.part.temperature);
double _maxCryoEnergyTransfer = maxCryoElectricCost * coolingEfficiency;
double excessHeat = (radiatorData.Energy - radiatorData.MaxEnergy);
excessHeat /= (double)(radCount + cooledParts);
double _maxEnergyTransfer = radiatorData.Part.temperature >= base.part.temperature ? this.maxEnergyTransfer : _maxCryoEnergyTransfer;
double val = Math.Min(Math.Max(0, thisRadiator.EnergyCap - thisRadiator.Energy), _maxEnergyTransfer);
double liftedHeatFlux = Math.Min(val, excessHeat);
if (this.Dfld_XferBase.guiActive)
{
this.D_XferBase = liftedHeatFlux.ToString();
}
liftedHeatFlux *= Math.Min(1.0, useHeatPump ? cryoEnergyTransferScale : this.energyTransferScale);
if (useHeatPump)
liftedHeatFlux *= refrigerationThrottle;
if (liftedHeatFlux > 0.0)
{
radiatorData.Part.AddThermalFlux(-liftedHeatFlux);
base.part.AddThermalFlux(liftedHeatFlux);
}
if (this.Dfld_Excess.guiActive)
{
this.D_Excess = excessHeat.ToString();
}
if (this.Dfld_HeadRoom.guiActive)
{
this.D_HeadRoom = val.ToString();
}
if (this.Dfld_XferFin.guiActive)
{
this.D_XferFin = liftedHeatFlux.ToString();
}
}
for (int i = 0; i < this.compensatedParts.Count; i++)
{
Part part = this.compensatedParts[i];
if (!(part.temperature < Math.Round(part.maxTemp * part.radiatorMax, 4)))
{
double conductionFlux = part.thermalConductionFlux + part.skinToInternalFlux;
if (conductionFlux > 0)
{
double compensatedFlux = Math.Min(conductionFlux, CoolingEfficiency(part.temperature, this.part.temperature) * maxCryoElectricCost) * refrigerationThrottle / radCount;
part.AddThermalFlux(-compensatedFlux);
base.part.AddThermalFlux(compensatedFlux);
}
}
}
}
}
public void print(string msg)
{
MonoBehaviour.print ("[ModuleRealActiveRadiator] " + msg);
}
}
}