Factorio

Factorio

View Stats:
Malidictus Jul 17, 2021 @ 7:41am
How do fluid mechanics work?
Preamble

Before I ask, let me explain where I'm at what what I'm NOT asking. I'm not looking for practical advise to solve a specific problem (how many pipes, pumps how often, what is throughput) so I don't have examples to give. I'm looking to understand the underlying system, in the hopes that this knowledge will help me solve my own more specific problems as they occur. I've also searched for answers here on this forum, but haven't found any. Threads about, but most of them deal with specific problems and don't go into the underlying tech. Many of them are very old, as well - from before the Fluid System overhaul.

I've tried all the resources I could find. I've read the Fluid System[wiki.factorio.com] article on the Wiki. It mostly gives practical information but doesn't get into the underlying system. It says THAT flow rate depends on the difference in fluid level between container, but gives no specific relationship. It also makes no mention of base level or height of containers. I've read the entry on Fluid Box[wiki.factorio.com] on the Wiki and know that raw fluid volume doesn't always correspond to fluid level. Taller/higher buildings will generally push fluid harder into shorter ones and vice versa.

The closest I've come to a systems breakdown is the Friday Facts #260[factorio.com] article on the new fluid system which has SOME explanation behind fluid mechanics. I'm not sure I understand it, however, so here we are.



The question

How do fluid mechanics actually work in Factorio? What computation determines the flow rate between two containers of different fluid level? Let's say I have 2 joined containers without pumps involved. For an arbitrary level of fluid in each, how can I calculate the amount of fluid flowing from one to the other in a given update tick?



The experiment

For this experiment, I'm using standard pumps and some non-standard pipe components. The system is supplied with an overabundance of infinite water on the input end and an infinite void on the output end. Only the system should matter for determining flow.

In example 1, I have a pump connected to 1 pipe segment connected to another pump. This gives me a flow rate of 6000/s with the pipe segment constantly full. The pipe segment holds 100 fluid, meaning my pumps are able to push 60*100 fluid through it, or 100 fluid per tick. The entire container's volume is being moved per tick.

In example 2, I have a pump connected to 2 pipe segments connected to another pump. This gives me a flow rate of 3000/s with both pipe segments half-full. The system appears to be able to move only 50 units of fluid between the pipe segments per tick. Assuming that on every tick, pipe segment 1 (on the input side) is full and pipe segment 2 (on the output side is empty), that means the game is pushing half the fluid height difference between them as flow per tick.

In example 3, I have a pump connected to 2 pipe segments connected to another pump. This gives me a flow rate of 2250/s. However, the steady state volume of each pipe segment is volatile and depends on the order in which pipes are built. If built input-to-output, the volumes are 62.5, 31.3, 37.5 respectively for pipe segments 1,2,3 in the order of input-to-output. If built in reverse (output-to-input), volumes is 62.5, 68.8, 37.5, respectively. If input and output pipe segments are built first and the middle build last, volumes are 100, 31.3, 37.5.

I don't know why this is, but I have a few guesses. Firstly, the last segment's steady state volume is always the same - 37.5. That's 37.5 fluid per tick, or 2250 fluid per second at 60 ticks per second. Again, full container volume appears to transfer per tick, and the steady state volume in the last container is what determines flow. But why the difference in the others?

I've tried doing some of the calculations myself, but I'm not entirely sure about the actual mechanics behind how fluid moves. The article states that all pieces with just two pipe connection sockets (so anything that's not an intersection) are calculated in a single tick. Pipe segments calculate the amount of fluid they intend to push to their neighbours first, then flow is evaluated output-to-input in a single tick. The problem is I still don't know how "fluid to send to neighbour" is calculated.

My BLIND GUESS is pipes push 50% of the fluid level difference per tick as that would - ignoring all other factors - equalise fluid levels in a single tick. I don't know if that's the case because a tank connected to another tank takes quite a while to equalise. This could be because tanks are technically "junctions" and so their interactions are evaluated on separate ticks, but even then - flow rate between the tanks diminishes the closer they are to equilibrium.

A 50K modded tank draining into another 50K modded tank takes quite a while to equalise - 20 seconds or so. A 2K modded pipe segment draining into another 2K modded segment takes relatively a lot less time. This leads me to suspect that there's some kind of throttle on absolute flow between segments besides just fluid level differential. Otherwise, all volumes regardless of absolute size would equalise at the same rate given the same relative level difference. 50K to 0 would equalise the same as 2K to 0, and that doesn't happen. Either there's a scale based on size, or there's some kind of flow throttle. Throttle seems unlikely, however, as gigantic modded 450-size tanks don't take 9 times longer to equalise than smaller 50K modded tanks.



Conclusion

I'm left unsure as to how the fluid system works. I know fluid containers will attempt to push fluid into containers with a lower level than them, but I don't know what determines the amount of fluid they attempt to push per tick, nor how that scales with size. As per the Wiki, pumps don't create "pressure" so much as they simply disregard fluid level and always "request" their full container's worth of fluid be pushed into them from whatever's at their input. They SHOULD work like pipe segments with that caveat, but that still leaves me with a question of calculating flow per tick.

The Flow System article itself doesn't make this clear, either. The author seems to have omitted the precise calculations in an attempt to not bore the audience, but that leaves a crucial element of the pipe system as an unknown. I know that a blue belt piece will move 45 items per second. I don't have any means of calculating on my own how much fluid a pipe would move, or how fast one container would drain into another. Those values simply aren't out there, or at least I can't find them.

If anyone has an idea of the specific way in which flow between containers is derived from the fluid level differential, I would love to hear it.
< >
Showing 1-6 of 6 comments
Warlord Jul 17, 2021 @ 8:05am 
I'm looking to see if there are actual good numbers for how much fluid flows per second based on relative fluid levels. I'm looking at one post[forums.factorio.com] that has an equation, but it seems to describe the "pressure" level there. It may go on later to explain how the pressure relates to exact flow of liquid later on, but it's taking me some time to parse the info since the pictures all seem to have been blackhole'd.

Another post[forums.factorio.com] has some info, but upon review it seems to be mostly someone complaining that the actual level of liquids in a setup don't seem consistent.

If you find a Factorio forum post about liquids, be sure to read the entire post. The original post may not have the info, but it's quite common for more info to be experimented out in replies that may not get posted in the OP. Also, look around in the factorio forums for other water-related posts. People in there can get quite focused on numbers, much more so than any post here on steam.

One bit of info I want to provide though, is to say that I BELIEVE that the majority (entirety?) of the fluid overhaul system was eventually removed/reverted due to a performance bug. I don't recall hearing that they abandoned plans, just put them on hold. But it's been quite some time since then with no more news.

Edit: That first link may have it. After showing a bunch of setups, he then provides a formula that relies on the "pressure" number from up above and should then give you an actual number (per tick) of liquid flows between two entities.
Last edited by Warlord; Jul 17, 2021 @ 8:08am
Fel Jul 17, 2021 @ 8:14am 
At the bottom of that wiki page, there are also links to three external places (two on the official forums and one on reddit), two of them with math (sadly the one on the forum no longer has its pictures but on the last page there is a link to the web archive version with images.

In the overwhelming majority of cases you don't need anything other than the table in the fluid system page you linked.
If you know the throughput you need, you lookup how many pipe segments at most you could use between pumps and that's about it.

Not that I don't understand wanting to know the systems completely, I tend to be like that too but when it becomes too complex I tend to fall back on using reliable data like that table as the basis instead of delving head first into hours of testing and math (because it kind of turns into a job rather than a game at that point).
Malidictus Jul 17, 2021 @ 8:57am 
Originally posted by Warlord:
I'm looking to see if there are actual good numbers for how much fluid flows per second based on relative fluid levels. I'm looking at one post[forums.factorio.com] that has an equation, but it seems to describe the "pressure" level there. It may go on later to explain how the pressure relates to exact flow of liquid later on, but it's taking me some time to parse the info since the pictures all seem to have been blackhole'd.

A "pressure" measurement is not entirely unreasonable given what I know of the fluid system, but that pressure rating almost always seems to disregard base and height of containers, only ever considering total volume. If all fluid containers are at base level 0 and have a height of 1, this makes sense.

For whatever reason, the Factorio developers set all of their fluid tanks to have a height of 1 - same height as pipes. In the fictional physics of the game, this means tanks are all pancakes - short, squashed round disks at near-ground-level. That's why a tank and a pipe system large enough will equalise to 50% of each other's total volume, where in reality a tall tank would actively push fluid into the pipes at above "volume equilibrium" level.

Why is this important

This whole train of thought started when I dug into the Fluid must Flow mod as a result of a discussion thread[mods.factorio.com]. That has somewhat non-standard settings. By default, all pipe segments are of height 2 (so double the height of normal pipes and tanks), except the Pipe to Ground segment - that's of height 4. It looks like an underground pipe, but behaves like a pipeline overpass, meaning that it resists filling to more than half capacity (because half of its volume is above the tops of other pipes) and aggressively drains into all nearby pipe segments. A pump just before a Pipe to Ground segment, then, will increase throughput DRAMATICALLY as the pipe-to-ground segment itself will act as a pump for segments down the line.

My guess is that the developers of the mod meant for the Pipe to Ground segment to be double height because it extends one level BELOW other pipes but didn't change its base level stat. As an experiment, I changed its base level state and that dramatically changed its behaviour. With a base level of -2 and a height of 4 (vs. other pieces with a base level of 0 and a height of 2), the Pipe to Ground segment acts like a fluid trap, aggressively drawing fluid from surrounding segments and refusing to empty above half-way. A pump after the segment, then, greatly increases throughput because the pump is able to empty it and the segment acts as a pump for segments before it.

When calculating flow, that matters a great deal because the level of equilibrium between two segments - and thus the pressure differential / pressure column - isn't always a direct ratio between their current and max volumes. Items with a high base level will aggressively push fluid into items with a lower base level while items with a high height will find equilibrium levels with a much lower portion of their total volume relative to items with a low height they're attached to.

That's mostly from the Fluid Box link I featured at the top, and some of my own experimentation. I personally believe that Vanilla Fluid Tanks should have a height of at least 2 if not 4. That would make them difficult to fill, requiring pumps but would make them very easy to empty since their height would push fluid with the force of a pump until they drain to below half/quarter volume.

That part of the fluid system I do understand, though :) At least I think I do...



Originally posted by Warlord:
One bit of info I want to provide though, is to say that I BELIEVE that the majority (entirety?) of the fluid overhaul system was eventually removed/reverted due to a performance bug. I don't recall hearing that they abandoned plans, just put them on hold. But it's been quite some time since then with no more news.

Well, that's... unfortunate. I personally thought that was a pretty clever bit of design. The last time I dealt with the fluid system was ~0.17/0.18, so I was hoping it had improved by then. I was hoping that this wasn't happening any more. Typically when it comes to modelling graphs in software, Factorio's fluid system and Barotrauma's old signal system were my go-to examples of doing it wrong. Because they're parsed depth-first, you end up with significant race conditions subject the order in which items are created and evaluated.

The New Fluid System's proposal of establishing a direction of flow, evaluating flow numbers input-to-output and then moving fluid output-to-input in a single tick sounded very clever. It makes me sad to hear it didn't make it into the game. Would explain the really odd behaviour I was seeing trying to push large volumes of fluid through narrow systems, though. Ugh.



Originally posted by Fel:
Not that I don't understand wanting to know the systems completely, I tend to be like that too but when it becomes too complex I tend to fall back on using reliable data like that table as the basis instead of delving head first into hours of testing and math (because it kind of turns into a job rather than a game at that point).

Unfortunately, this falls under my "specific problem" disclaimer. The Wiki's shorthand is REALLY good for the specific problem of Vanilla pipes and pumps - it's a quick-reference table. However, it doesn't help with modded pumps, modded pipes or pipe segments with unequal volume. As I mentioned above - the Fluid Must Flow mod was my primary reason to dig into the fluid system (this time and last time), and that mod has both of these caveats. Actually, it also has a third - it also has pipe segments with unequal height.

The mod discussion thread I mentioned before shows some discrepancies in that mod, specifically that pipes with a larger container volume tend to create faster flow than pipes with a lower container volume. The mod varies pipe volume by segment length, I believe in an attempt to cut down on flow loss for multiple stacked elements, but it creates the opposite problem where pipe corners and junctions drastically throttle flow, instead.

An example I didn't show in my OP was a pump pumping into a modded pipe segment with a large volume (2000 units). The pipe was able to push it full 12000 units/s throughput through that, putting only 200 units of fluid into the pipe segment as a steady state. That makes sense, given that 200 units at 60 ticks per second is 12000 units per second. Vanilla pipes have a volume of just 100, which is why pump-to-pipe-to-pump is only 6000 - 60*100 volume.

---

Apropos of nothing, but one of the links had an interesting formula in it it:

current pressure = zero-pressure + (max pressure - zero-pressure) * water level / max capacity.

The idea of modulating flow based on not just just the fluid level differential between two containers but also on the fluid volume level differential between current and maximum volume is interesting. I thought that perhaps it could explain why tanks drain so slowly between each other, but I'm not sure it does. I suspect there's some absolute value somewhere in the game which slows down flow over larger quantities - that flow isn't just proportional.

In real live, pipe/connector diameter would limit flow between large volumes, but Factorio doesn't seem to have that aspect entirely. Two attached fluid tanks behave as though attached across a crossection of their entire volume, as I can see no setting for connector "size." Neither FluidBox nor PipeConnectionDefinition have any settings which could restrict flow, leading me to believe this restriction is more fundamental to the fluid system itself.
Malidictus Jul 17, 2021 @ 7:01pm 
Well, I'm still not sure about how the fluid system works in specific, but I ran a few more tests and discovered some interesting dependencies. One of them is fairly simple - the maximal possible throughput of a system is - at least in idealised circumstances - by the size of the smallest component. In the OP, we already established that a 100-capacity pipe will limit throughput to just 6000 units/s, as no more than 100 units of fluid can pass through that pipe per tick. 60 ticks per second, 60*100 = 6000 units of fluid per second.

This matters when you start dealing with mods. Back to Fluid Must Flow, the pumps (end points) have a listed maximum flow rate of 72000 units per second (6 times that of a normal pump, matching the 6 input/output pipe connectors). However, the volume of the pumps themselves is only 800, which hard-limits their flow rate down to 48 000/s (i.e. 60*800). That's the simplest, most idealised scenario I can create - pump to pump.

Now, something funny happens if I double the size of the pump's fluid box. Luckily, Fluid Must Flow exposes that through mod settings so it's convenient. Doing that actually produces a pumping speed of 76 800/s... of 72 000/s limit. Somehow, I managed to exceed the pump's speed limiter - and I know it's set correctly. I checked, and the Pump prototype's pumping_speed setting is set to 1200 per tick, 72 000 per second. So, either that setting is completely ignored, or there's something else strange going on.

I think there's something else strange going on, because the pump isn't full to capacity. At a capacity of 1600, it's only full to 1300, and the second pump itself is full to 38.2, both as a steady state. So clearly, even pump-to-pump, the fluid system does not like me transferring 1600 fluid per tick between containers. 76 800 flow is actually equal to 1280, which the UI rounds up to 1.3K in the display. This suggests to me that there's either some kind of fixed threshold or some kind of scaling reduction of flow, because the inability to shift full inventory between containers only kicks in after containers grow past a certain size. It's 5 AM so I can't really experiment to find exactly where that breakpoint is, but it does exist. The larger the volume that containers attempt to shift between then per tick, the lower the flow rate becomes relative to what it could be.

Just to be sure, I checked the PipeConnectionDefinition type, thinking that maybe that had a setting for maximum flow, or flow reduction or something, but... it doesn't. It has settings for position on the object, underground distance and whether it's input or output. No setting for flow. So either flow diminishing returns are controlled elsewhere in the fluid system, or there's some non-exposed setting for flow throttling in the pipe connection type that we can't see.

This is where the quick-reference table on the Wiki falls short. It's designed for 100-volume pipe segments and nothing else. Once segment sizes grow past a certain point, confounding variables seem to make themselves apparent that the quick-reference table doesn't account for. I'm genuinely not sure why fluid transport has to be this complex in a game like this. It seems like a simpler, more straightforward system would work just as well in larger networks. Trying to use a fluid simulation ends up with opaque mechanics, leaving players with insufficient data on which to make informed decisions.

I'll try to keep digging, but the resources I found so far seem to lean closer to real-world flow mechanics and less so towards Factorio's unique take.
Alpha and Omega Jul 17, 2021 @ 8:20pm 
In your initial post you mention the "fluid overhaul". I'm sure you've seen many posts about the overhaul on the official blog and other places.

However this overhaul was never implemented and the game still has the nonsensical barely working and/or arguably not working fluid mechanics described by the old posts you've found.

Here's a link to a post where they said it was cancelled: https://forums.factorio.com/viewtopic.php?p=475106#p475106

There's also a blog post about it somewhere.

The first thing to understand about the fluid system is that each liquid container is updated in the order it was built. This means that flow calculations or formulas are somewhere between meaningless and impossible because it depends on factors that have nothing to do with the geometry of the system in question.
Last edited by Alpha and Omega; Jul 17, 2021 @ 8:27pm
Malidictus Jul 18, 2021 @ 4:37am 
Originally posted by Alpha and Omega:
The first thing to understand about the fluid system is that each liquid container is updated in the order it was built. This means that flow calculations or formulas are somewhere between meaningless and impossible because it depends on factors that have nothing to do with the geometry of the system in question.

Yeah, I was starting to pick up on that just through my own testing. I noted odd steady state fluid levels in the OP when dealing with 3 or more pipe segments per fluid system which seemed to depend on the order in which I built the items. I also linked to a video in a later response where I was able to get anywhere between ~3000 and ~7000 units of flow per second from the same "figure 8" set of pipes based on the order in which I built them. Sometimes water would flow along all three channels, sometimes it would flow along only two, sometimes it would actually flow BACK along one and really debilitate throughput.

One of the ways in which I've tried to address this is by avoiding pipe junctions as much as I can. My goal is for all of my pipe networks to be tree graphs at most. That is to say - I can either have multiple outputs or multiple inputs but not both at the same time. Seems to get around most of the race conditions in the current fluid system, as I don't get these weird backflows.

It is disappointing, though. Game after game, developer after developer drops the ball on graph model implementation, and always for the same reason - race conditions. I know that's typically a term of parallel programming, but it should apply to any system where multiple objects can read from and write to the same data, where the order of operations creates cascading changes.

This is why I'm so sad to hear that the new system was abandoned. What it proposed was such a clever solution. Rather than trying to move fluid between pipe segments one at a time, it calculated a "desired" amount of fluid to move for the entire system, then moved that amount of fluid before recalculating. This all but entirely eliminates race condition issues, but it never happened and that's a pity. I hate seeing clever programming go to waste like that.
< >
Showing 1-6 of 6 comments
Per page: 1530 50

Date Posted: Jul 17, 2021 @ 7:41am
Posts: 6