|
| 1 | +using System; |
| 2 | +using System.Collections.Generic; |
| 3 | +using System.Globalization; |
| 4 | + |
1 | 5 | namespace RealFuels.Tanks |
2 | 6 | { |
3 | 7 | internal sealed class BgBoiloffCache |
4 | 8 | { |
5 | | - internal readonly string DataVersion; |
6 | 9 | internal readonly int MliLayers; |
7 | 10 | internal readonly BgTankEntry[] Tanks; |
8 | | - internal readonly double[] InternalTemps; // mutable, parallel to Tanks; -1 = uninitialized |
| 11 | + internal readonly double[] InternalTemps; // mutable, parallel to Tanks |
| 12 | + internal readonly double[] FluxScratch; // mutable per-tick scratch for Q_kW pre-pass |
| 13 | + |
| 14 | + internal readonly double CoolerInputKW; // (0 if no cooler installed) |
| 15 | + internal readonly double CoolerFrac; // fraction-of-Carnot at CoolerLowestTempK |
| 16 | + internal readonly double CoolerLowestTempK; // cold-side T of the cooler |
9 | 17 |
|
10 | | - internal BgBoiloffCache(string dataVersion, int mliLayers, BgTankEntry[] tanks) |
| 18 | + internal BgBoiloffCache(int mliLayers, BgTankEntry[] tanks, |
| 19 | + double coolerInputKW, double coolerFrac, double coolerLowestTempK) |
11 | 20 | { |
12 | | - DataVersion = dataVersion; |
13 | 21 | MliLayers = mliLayers; |
14 | 22 | Tanks = tanks; |
15 | 23 | InternalTemps = new double[tanks.Length]; |
16 | | - for (int i = 0; i < tanks.Length; i++) InternalTemps[i] = -1d; |
| 24 | + FluxScratch = new double[tanks.Length]; |
| 25 | + CoolerInputKW = coolerInputKW; |
| 26 | + CoolerFrac = coolerFrac; |
| 27 | + CoolerLowestTempK = coolerLowestTempK; |
| 28 | + } |
| 29 | + |
| 30 | + internal static BgBoiloffCache Build(string data, string coolerData, int mliLayers) |
| 31 | + { |
| 32 | + var tanks = new List<BgTankEntry>(); |
| 33 | + |
| 34 | + foreach (string entry in data.Split(';')) |
| 35 | + { |
| 36 | + if (string.IsNullOrEmpty(entry)) continue; |
| 37 | + string[] split = entry.Split(','); |
| 38 | + if (split.Length != 7) continue; |
| 39 | + |
| 40 | + string resourceName = split[0]; |
| 41 | + if (!double.TryParse(split[1], NumberStyles.Float, CultureInfo.InvariantCulture, out double boilingPointK)) continue; |
| 42 | + if (!double.TryParse(split[2], NumberStyles.Float, CultureInfo.InvariantCulture, out double tankAreaM2)) continue; |
| 43 | + if (!double.TryParse(split[3], NumberStyles.Float, CultureInfo.InvariantCulture, out double conductWPerK)) continue; |
| 44 | + if (!int.TryParse(split[4], out int isDewarInt)) continue; |
| 45 | + if (!double.TryParse(split[5], NumberStyles.Float, CultureInfo.InvariantCulture, out double hsp)) continue; |
| 46 | + if (!double.TryParse(split[6], NumberStyles.Float, CultureInfo.InvariantCulture, out double structThermalMassKJ)) continue; |
| 47 | + |
| 48 | + PartResourceDefinition resDef = PartResourceLibrary.Instance.GetDefinition(resourceName); |
| 49 | + if (resDef == null || resDef.density <= 0d) continue; |
| 50 | + if (!MFSSettings.resourceVsps.TryGetValue(resourceName, out double vsp) || vsp <= 0) continue; |
| 51 | + |
| 52 | + tanks.Add(new BgTankEntry |
| 53 | + { |
| 54 | + Name = resourceName, |
| 55 | + Vsp = vsp, |
| 56 | + Density = resDef.density, |
| 57 | + BoilingPointK = boilingPointK, |
| 58 | + TankAreaM2 = tankAreaM2, |
| 59 | + ConductWPerK = conductWPerK, |
| 60 | + IsDewar = isDewarInt != 0, |
| 61 | + Hsp = hsp, |
| 62 | + StructThermalMassKJ = structThermalMassKJ, |
| 63 | + }); |
| 64 | + } |
| 65 | + |
| 66 | + double coolerInputKW = 0d, coolerFrac = 0d, coolerLowestTempK = 0d; |
| 67 | + if (!string.IsNullOrEmpty(coolerData)) |
| 68 | + { |
| 69 | + string[] cSplit = coolerData.Split(','); |
| 70 | + if (cSplit.Length == 3 |
| 71 | + && double.TryParse(cSplit[0], NumberStyles.Float, CultureInfo.InvariantCulture, out coolerInputKW) |
| 72 | + && double.TryParse(cSplit[1], NumberStyles.Float, CultureInfo.InvariantCulture, out coolerFrac) |
| 73 | + && double.TryParse(cSplit[2], NumberStyles.Float, CultureInfo.InvariantCulture, out coolerLowestTempK)) |
| 74 | + { |
| 75 | + // ok |
| 76 | + } |
| 77 | + else |
| 78 | + { |
| 79 | + coolerInputKW = 0d; coolerFrac = 0d; coolerLowestTempK = 0d; |
| 80 | + } |
| 81 | + } |
| 82 | + |
| 83 | + return new BgBoiloffCache(mliLayers, tanks.ToArray(), coolerInputKW, coolerFrac, coolerLowestTempK); |
| 84 | + } |
| 85 | + |
| 86 | + internal void InitTemps(ProtoPartModuleSnapshot proto_module) |
| 87 | + { |
| 88 | + // Seed InternalTemps from the persisted TANK nodes |
| 89 | + var tempLookup = new Dictionary<string, double>(StringComparer.Ordinal); |
| 90 | + foreach (ConfigNode tankNode in proto_module.moduleValues.GetNodes("TANK")) |
| 91 | + { |
| 92 | + string tName = tankNode.GetValue("name"); |
| 93 | + string sVal = tankNode.GetValue("internalTemp"); |
| 94 | + if (tName != null && double.TryParse(sVal, NumberStyles.Float, CultureInfo.InvariantCulture, out double t)) |
| 95 | + tempLookup[tName] = t; |
| 96 | + } |
| 97 | + |
| 98 | + for (int i = 0; i < Tanks.Length; i++) |
| 99 | + { |
| 100 | + InternalTemps[i] = tempLookup.TryGetValue(Tanks[i].Name, out double v) && v > 0 |
| 101 | + ? v : Tanks[i].BoilingPointK; |
| 102 | + } |
17 | 103 | } |
18 | 104 | } |
19 | 105 |
|
|
0 commit comments