Yothiel Posted November 15, 2017 Share Posted November 15, 2017 So, since I couldn't find any good source on how heat transfer actually worked in this game, my curiosity got the better of me. The decompiled C# DLL might be easy to read and does have some stuff, but most of the tasty bits required me to dive into the disassembly of the C code from the SimDLL. In that DLL, I've located three main functions handling most of the following cases: Cell/Cell transfers Cell/Building transfers Cell/Entity transfers (which includes dupes, geysers, mined element chunks and stored items, pretty much everything which is neither a building or a cell) Most of the following should be valid on both the Oil version and the Automation preview. Reading a proper introduction on thermal transfers may be useful before going over this text, since I'll quickly jump into technical details. A quick foreword on calculus notations I will use: |x| means "absolute value of x". If x > 0, this is equal to x, else it equals -x. Δ (delta) has no actual signification, but is used in names to denote a variation between two steps/elements (for instance, I would be enclined to use "ΔT" if I wanted to put a name on the "T2-T1" value) clamp(x, y, z) assumes that y is lower than z projects the value of x in the interval [y;z]. It is equal to x if x >= y and x <= z, or y if x < y, or z if x > z. Cell/Cell transfers Okay, so first let's go over the basics. I'll list the fundamental properties and what notation I'll use for them. I'll also indicate the units used in the game, though you should pay them no mind since dimensional correctness is not ensured (especially, most values you'd expect to be watts/joules will actually be used as kilowatts/kilojoules). Each cell of the game have the following properties: a temperature noted T (displayed in K) a mass noted m (displayed in kg) an insulation factor noted f (dimensionless, varies between 0 (total insulation) and 255 (no insulation). Actually, this value is always 255, excepted insulated tiles which have 2. an element (e.g. liquid hydrogen, sandstone, etc) The same chemical component in two different states (e.g. gas hydrogen and liquid hydrogen) are referred with different elements. Each element has the following properties: State information (e.g. gas/liquid/solid of course, but also whether it is unbreakable or temperature-insulated like neutronium) a thermal conductivity noted k (the value displayed in W/m/K in the game) a specific heat capacity noted c (the value displayed in J/g/K in the game) Surface-Area multipliers for interacting with each of the three states gas/liquid/solid. As a rule of thumb, liquids have a multiplier of 25 for interacting with other liquids, and gas also have a multiplier of 25 for interacting with solids. All other multipliers have a value of 1. Let's note them S for now. If you're being curious, these element values seem to come from some Unity package and are loaded into the simulation, not stored in the DLL. Now, let's define even MORE values which are derived from the above ones: the insulated conductivity noted k' is derived from (gasp) the insulation factor and the thermal conductivity using the following formula: k' = k * (f/255)² the heat capacity, noted C is derived from mass and specific heat using the following formula: C = c * m the thermal energy, noted Q, derived from the heat capacity and the temperature, using the following formula : Q = C * T Okay, that should be enough for now. Let's take a "Cell 1" and a "Cell 2" (I'll suffix each of their properties with their number, e.g. T1 or T2). Here are the steps for determining the heat they transfer during one game tick: if any of the elements has the "isolated" flag in its temp (e.g. neutronium), no transfer is done if |T2 - T1| < 1, no transfer is done (even when temperature are stabilized, there may still exist a gradient in temperatures) A first candidate for the amount of energy transferred during a duration of Δt is given by the formulaΔQ = Δt * min(k'1, k'2) * (T2 - T1) * (S1[type of cell 2] * S2[type of cell 1]) Note that for one game tick, Δt should be 0.25 (4 ticks/second). A first clamping is done and results in a new candidate: ΔQ' = sign(T2-T1) * min(|ΔQ|, |Q2-Q1|/8) if |ΔQ'| < 1.0E-4, no transfer is done Candidates for the new temperatures are computed using the following formula:T'1 = T1 + ΔQ' / C1 and T'2 = T2 - ΔQ' / C2 if (T2 - T1) * (T'2 - T'1) < 0 (the order of cell temperatures changed), both T'1 and T'2 are affected an equilibrium temperature computed with the formula: T'1 = T'2 = (Q1 + Q2) / (C1 + C2) More clamping occurs to prevent temperatures from changing by more than |T2 - T1| / 4: if |T'1 - T1| > |T2 - T1| / 4, then T'1 = T1 + (T2 - T1)/4 likewise if |T2' - T2| > |T2 - T1|, then T'2 = T2 - (T2 - T1)/4 Final heat transfer is ΔQ'' = sign(ΔQ') * min(|T1' - T1| * C1, |T2' - T2| * C2) and final temperatures for the next game tick are:T''1 = T1 + ΔQ'' / C1 and T''2 = T2 - ΔQ'' / C2 and voilà! So, for some examples with actual figures Cell 1 is 100kg of water at 370K, Cell 2 is 200kg of polluted water at 315K ΔQ = 0.25 * min(0.609, 0.58) * (315-370) * 25 * 25 = -4984.375 (note the two "25" surface area multipliers when two liquids interact with each other!) With Q1 ~=1.5E5 and Q2 ~=3.6E5, ΔQ' = ΔQ. T'1 = 370 -4984.375 / (100 * 4.179) ~= 358K and T'2 = 315 + 4984.375 / (200 * 6) ~= 319.15K SInce the temperature changes are within |T2 - T1|/4, no further clamping is needed: these are the final temperatures. Cell 1 is 1kg of hydrogen at 215K, Cell 2 has a metal tile of tungsten. Now, non-permeable tiles will fill the cell with the same material they are composed of, and both the tile and the cell will interact as a single entity, so we have 200kg of tungsten (100kg from the tile and 100kg from the cell) at, let's say, 300K for cell 2. ΔQ = 0.25 * min(0.168, 60) * (300 - 215) * 25 * 1 = 89.25 Again, ΔQ' = ΔQ, so T'1 = 215 + 89.25 / (1 * 2.4) = 252.1875 and T'2 = 300 - 89.25 / (100 * 0.134) = 293.34 Since |T'1 - T1| > |T2 - T1|/4, we replace it by the value T'1 = 215 + (300 - 215) / 4 = 236.25. ΔQ'' = min(|236.25 - 215| * (1 * 2.4), |293.34 - 300| * (100 * 0.134)) = min(51, 89.25) = 51 Final temperatures are T''1 = 215 + 51/(1 * 2.4) = 236.25 and T''2 = 300 - 51/(200 * 0.134) = 298.097K Cell 1 is abyssalite at 350K and any weight, Cell 2 is granite at 315K and any weight. ΔQ = 0.25 * min(2, 0.00001) * (315 - 350) * 1 * 1 = -8.75E-5 Since |ΔQ| < 1E-4, no transfer is done. Basically, abyssalite will only transfer heat with other solids / liquids until they are within a 40K range of each other. An insulated tile of abyssalite will never transfer heat with another cell (needs a delta of at least 26010K to exchange with a gas, or 650250K for a solid/liquid If you're wondering about that "thermal energy delta" rule, consider the following case:Cell 1 is 1kg of hydrogen at 320K, cell 2 is 800kg of gold amalgalm at 6.4K (not a naturally found temperature, but you'll understand the choice) Here, Q1 = 2.4 * 1 * 320 = 768, and Q2 = 0.15 * 800 * 6.4 = 768 This causes ΔQ' to be capped at |Q2 - Q1| / 8 = 0: no transfer is done despite the huge temperature difference and the relatively good conductivities. Making sense to you? Yeah, neither to me Cell/Building transfers Okay, now let's add introduce the building! That term pretty much covers anything you build, but also the ruines you can find prebuilt (even though most of that stuff isn't really doing heat transfer). In the simulation, buildings only interact with the cells they cover, though some specific buildings also interacts with their contents (that's in the C# part of the game and not covered here) Let's reuse the same properties / notations as the cell, but with a few more definitions: left/right/top/bottom coordinates, used for determining the cells interaction with the building. They can be used to define an area, noted A a capacity per cell, noted C', and derived from the heat capacity (the usual C = c * m) and area through the formula: C' = C / 5 / A (note the infamous factor of 5 for all building-related heat transfers) An operating heat creation per tick, noted W. This operating heat is displayed in the game as the generated heat by the building, with a number of catches: the displayed value is actually an addition of both the operating heat, and an "excess" heat, the latest being applied for some reason by the C# part of the game and will be listed in the Other transfers part (excess is directly applied to the cell, operating heat is applied to the building which may transfer it to the cell). To see which part is operating and which part is excess and which part is operation, you can hover your cursor over "Heat Production" in the Info / Status tab of an active the value is displayed as watts, but actually used as kilowatts the value displayed has been multiplied by a 5 factor (strictly speaking this is not the same factor as the one applied to the mass, but the values are probably identical on purpose all this considered, you must basically take the value displayed as "normal operation" and divide it by 5 to get the value for W. Knowing that, there are less rules for cell/building heat transfers. Cell values will be suffixed with 1 (e.g. T1), and building values with 2 (e.g. T2): For each game tick and for each building , start by defining an energy accumulator ΔQtot initialized at 0 For each of the cell inside the left/right/top/bottom area of : If the element id is matching a specific value (Vacuum I'm guessing), no transfer is done, go to the next cell else, let's define the heat capacity Chot. If T1 < T2, Chot = C'2, else Chot = C1 Let's also define Tmin = min(T1, T2) and Tmax = max(T1, T2) Candidate value for heat transfer: ΔQ = Δt * k'1 * k2 * Chot * (T1 - T2) * 0.005 * x, where x is a game-global value usually equal to 100 (the only time I saw it with a different value is on the first few ticks after starting/loading a game, in which case it's at a low value like 0.01). candidate new temperatures are clamped to the [Tmin, Tmax] interval: T'1 = clamp(T1 - ΔQ/C1, Tmin, Tmax) and T'2 = clamp(T2 + ΔQ/C'2, Tmin, Tmax) If (T1 - T2) * (T'1 - T'2) < 0 (order of temperatures changed), values are replaced by the equilibrium temperature T'1 = T'2 = (C1 * T1 + C'2 * T2) / (C1 + C'2) T'1 is set to the cell as its new temperature ΔQtot is increased by C'2 * (T'2 - T2) after looping over all the cells for this building, its final temperature for this game tick will be: T''2 = T2 + (ΔQtot + W * Δt) / (C'2 * A) A couple examples: An active sandstone compost at 275K is sitting on 4 cells, each with 1kg hydrogen at 320k. Its operating heat creation is shown as 5, so W = 1 The hydrogen is the hot body here, so for each cell, Chot = 1 * 2.4 ΔQ = 0.25 * 0.168 * 2.9 * 2.4 * (320 - 275) * 0.005 * 100 = 12.6544 In this case there will be no clamping, and the heat transfer will be the same for each cell, so each cell's temperature will become by T'1 = 320 - 12.6544 / 2.4 = 314.7K (before excess heat is applied), while the compost's temperature will be T''2 = 275 + (4 * 12.6544 + 1 * 0.25) / (0.8 * 800 / 5 / 4 * 4) = 275.4K. Take an obsidian pipe at 275K is sitting in 1kg of hydrogen at 320K. Take an obsidian insulated pipe at 275K sitting in another 1kg of hydrogen. Note how there is no place for pipe insulation factor: both pipes will transfer the same heat (though the temperature insulated pipe will have a slower increase because of its increased mass) Take the same case as above, but flip the pipe and the hydrogen temperatures. Now, the transferred heat will be proportional to the capacity of the pipes, and the insulated pipe will transfer more heat (though their temperature will be the same) Cell/Entity transfers Entities have the usual mass / temperature / capacity / conductivity properties, and add the following concepts: A Surface Area Multiplier noted S (which, unlike Cell/Cell transfers, does not depend on element state). A thickness, noted L Pretty simple isn't it? Here are the steps. Cell values are suffixed with 1, Entity values with 2. An entity exchanges heat with the single cell it is associated to If it cannot exchange heat with this cell (i.e. vacuum), it will exchange heat with the cell below, at 1/4 the normal rate The candidate heat exchanged for a period Δt is ΔQ = Δt * S2 / L * min(k1, k2) * (T2 - T1) (the 1/4 factor is applied here if the entity exchange heats with the cell below its actual cell) if |ΔQ| > |Q1 - Q2| / 1000, ΔQ = sign(ΔQ) * |Q1-Q2| / 1000 (yeah, the nonsensical clamping based on thermal energy difference is back!) The candidate new temperatures are T'1 = T1 + ΔQ / C1 and T'2 = T2 - ΔQ / C2 if (T1 - T2) * (T'1 - T'2) < 0, the equilibrium temperature is back: T'1 = T'2 = (Q1 + Q2) / (C1 + C2) That's over! Now, there is an exception: items stored in a fridge (even unpowered) or a compost will interact with a virtual heat source of 277.15K (fridge) or 348.15K (compost), and will do so with a set conductivity of 1000. The cell will not receive / lose heat from that exchange (technically, you could destroy heat by repetitively putting muckroot in a fridge and getting it out, but that would not be very efficient) I think most entities have a S value of 1, and a thickness of 0.001. Some exceptions I've spotted: wheezewort have a S value of 10 Duplicants have a thickness depending on their clothes and the displayed value after conversion to meters (for 0.2cm, L = 0.002). There is one catch however that I managed to spot while debugging the code: thickness from the default clothes is actually not counted (so basically, even the cool vest will keep duplicants warmer than default clothes) Other transfers While this does seem a lot, there still are many cases not accounted yet when it comes to heat. Here is a non-exhaustive list: pipe/content transfer: uses a standard formula for determining the heat transfer, which is pretty much equivalent to the Cell/Entity one without the thermal energy clamping if you take S / L = 50 (source: C# code) building/cell transfer of "excess" heat: each cell receives the excess heat, divided by the area of the building, and this transferred heat is proportionally scaled down if the cell as less than 1.5kg of content (source: C# code) Building-specific heat creations/transfers (e.g. aquatuners, refineries, etc). Each case is different, and once again can be checked in human-readable decompiled C#, so I won't bother listing them. Heat exchange accompanying movement/exchange of liquids/gas: I can't tell you a thing about that, though it's probably the part which was responsible for the infamous "dripping bug" Heat propagation in gas: when a gas cell receives heat, it will send some of it to the cell above if it contains the same type of gas. If the cell is losing heat, it will instead propagate some of that loss to the cell below if it contains the same type of gas. This propagation continues until the next cell contains a different element, or if the transferred heat is too low. Source: experimentation in debug mode. any heat creation / destruction linked to element creation / destruction / conversion Okay, I think that covers pretty much I've been able to siphon so far. While most of this information may only be marginally useful, it may help understand some oddities such as: the "insulated" part of insulated pipes the excellent results of very conductive tiles (and the steel previously created by closed doors!) for exchanging heat with the far less conductive granite pipes. the actual effect of insulated tile (woosh this stuff is almost as good as abyssalite!) etc Feel free to add any information & let me know if something is unclear or if an error found its way in this huge text (which wouldn't surprise me tbh), and have fun trying (and probably failing) to size any radiator / cooling system! Link to comment Share on other sites More sharing options...
This topic is now archived and is closed to further replies.
Please be aware that the content of this thread may be outdated and no longer applicable.