Jump to content

ONIversity: Hydrodynamics - A Complete Description of Horizontal Flow For a Single Layer of Liquid Over a Solid

Recommended Posts

It's been a long week with lots of sleepless nights.  I think I've finally cracked liquid flow.  This is my first post in a new series, from ONI University.  Today we'll be studying fluid mechanics, namely the branch of hydrodynamics (liquid flow).  


In this post we’ll give an algorithm that perfectly predicts the horizontal flow of a single layer of liquid that lies on a horizontal flat surface. Applications of this algorithm, and multi-layer flow, will come in other posts. This post focuses solely on the algorithm, and you'll find a spreadsheet to play with as well.

Perfect Prediction? Who cares?

Once we understand exactly how a universe deals with liquids, we can build contraptions that utilize this.  Bead pumps, waterfalls, magma pumps, and more are going to be optimized.  For example, a water waterfall should hold itself through save load with a valve setting of 184.7462277, or 185 (I'll let you figure out which geometric series formula I used for this). We can optimize any contraption that utilizes moving liquid. We can explain exactly why the "Plinko Vacuum" approach only goes 7-8 tiles to the right, and predict how far left it will go with one 200kg load of water. We can optimize a design for a magma pump, similar to @Zarquan's work a few days ago. So many more contraptions can be built, with the ability to predict the future (it's what we do in real world science). 


We'll decipher how the game computes liquid flow along a single tile tall horizontal solid surface (with or without walls). This means that we are restricting ourselves to the case that (1) each tile of liquid has no more than the maximum mass of the liquid. These maximum masses were recently displayed in picture form here, but you can grab them from R9MX4's Material Handbook.


Hopefully all important liquid properties will soon be available in @f4rtux's ONI Database at oni-db.com.

We will also assume that (2) we are in a vacuum (though the computations do not change provided any gas has an escape route that it can move to). 


Note: I obtained the following information through testing (lots of debug), building models, trial and error, and lots of sleepless nights. I cannot guarantee this is how the game computes liquid flow, but all my observations agree perfectly with the model. I have not decompiled any code ( @Yothiel's approach to decrypting heat transfer), rather used collected data to build and test a model. 

Liquid Properties and Game Engine Notes

For this model, we need to pick a liquid. The key liquid properties (from the Material Handbook) needed for horizontal flow are the following:

  • MaxMass (Examples: MM = 740 kg for Naptha, MM=1000kg for water)
  • Viscosity (Examples: V=30 kg for Naptha, V=125 for water)
  • MinHorizontalFlow (Examples: MHF=10 kg for Naptha, MHF=0.01 for water)

Here are a few notes before we get in. 

  • The game engine updates the liquid properties every tick (0.2s) of the game.
  • The game performs computations iteratively, starting on the left and working right one tile at a time.
  • All displayed values appear truncated (not rounded), so the value 2895.99999734 will appear as 2895.9 (this made finding the model somewhat tricky, but knowing this simplifies further model finding).  This also means that if you manually try to add up the total liquid values, you often end up short a bit of liquid. The liquid is there, despite the actual value not being shown. 

The Algorithm

We now examine pseudocode for the function that returns the “NewMass” of a given tile. There are 4 input variables and 2 output variables. 

  • Input Variables:
    • CurrentMass - The current mass of the cell we are updating.
    • MassSentLeft  - The mass that the cell to the left took away, equal to the previous cell’s InflowMass.. If this value is positive, then some of the liquid from the current cell was sent left. If this value is negative, then the cell to the left sent liquid to our current cell. If the cell to the left, after its computation, does not have liquid in it, then this variable is zero. In space, liquid on the left side of the map does not flow left either, so the default value is zero. 
    • RightCellAvailable - TRUE/FALSE - If this liquid can inhabit the cell to the right, then this variable is TRUE. Otherwise, this variable is FALSE. 
    • RightMass - The mass of liquid in the cell to the right (0 if no liquid is there). 
  • Output variables
    • NewMass - The mass of liquid for the next tick of the game. 
    • InflowMass - This is the mass of liquid that gets pulled from the next cell. This value is the input “MassSentLeft” for the cell to the right, and can be positive or negative. 

Heuristically, the game finds the difference between the current cell, and the cell to the right, divides this difference by 4, and sends this amount to the lower mass tile. However, this simple model (which works great for a single blob of liquid) has a few quirks addressed below.

Here is the algorithm:

  1. TempMass = CurrentMass - MassSentLeft;    
        //The mass of this cell after removing what was sent to the cell to the left.
  2. If (RightCellAvailable = FALSE) THEN RETURN NewMass=TempMass and InflowMass=0;
        //This cell cannot pull or push any liquid to the right. The computation is done. 
  3. InflowUsingCurrent = (RightMass - CurrentMass)/4;  
        //The mass we should pull from the cell to the right, using the current mass.
  4. InflowUsingTemp = (RightMass - CurrentMass)/4; 
        //The mass we should pull from the cell to the right, using the temp mass.
  5. AdjustedInflowUsingTemp
    1. IF ( MassSentLeft<0 ) THEN AdjustedTempInflow = TempInflow - MassSentLeft/4;
    2. ELSE AdjustedTempInflow = TempInflow;
      //If the cell to the left caused our mass to increase, don’t include that mass in further computations. This keeps an increase in mass from moving more than one cell right. 
  6. UseFlow
    1. IF (AdjustedInflowUsingTemp>0 AND InflowUsingCurrent<0), THEN UseFlow=FALSE (0); RETURN NewMass=TempMass and InflowMass=0; 
      //If the cell to the left sent so much liquid to current cell that we went from having less liquid than the cell to the right to now having more liquid than the cell to right, stop. 
    2. ELSE UseFlow=TRUE(1) - Continue; 
  7. UnclampedFlow = whichever of AdjustedInflowUsingTemp and InflowUsingCurrent is closer to zero.  The following code would give this.
    1. IF ( | AdjustedInflowUsingTemp| < |InflowUsingCurrent| ) THEN UnclampedFlow = AdjustedInflowUsingTemp;
    2. ELSE UnclampedFlow = InflowUsingCurrent;
      //Just make sure you grab the flow with a smaller magnitude. 
  8. InflowMass
    1. IF ( UnclampedFlow < MinHorizontalFlow) THEN InflowMass = 0;
      //The game requires a minimum flow.
    2. ELSE IF (Unclamped Flow>Viscosity) THEN InflowMass=Viscosity;
      //The game has a maximum flow rate. The cell to the right will be sending this amount to the current cell. 
    3. ELSE IF (UnclampedFlow<-Viscosity) THEN InflowMass = -Viscosity;
      //This cell will drop by the viscosity, and send the mass right. 
    4. ELSE InflowMass = UnclampedFlow; 
  9. NewMass = TempMass+InflowMass;

Parts 5 and 6 above were the trickiest parts to decipher, as odd things can happen when you have liquids jostling around with high and low masses rapidly alternating from left to right. I’d love to have someone simplify the code above. 

Where is the Promised Spreadsheet?

Here is a google doc spreadsheet that performs all these computations for you, showing you the intermediate computations at each stage. Make a copy of the spreadsheet if you wish to edit it. 

The 4:9:3 rule

One simple application immediately follows from above. Drop 16kg of water on a tile. You'll see the following occur after 1 tick (0.2 s).


The left most tile (with the 4 on it) grabbed one fourth of the liquid, leaving 12 kg behind.  Then the middle tile sent 3 kg right (one fourth of the remaining 12kg). 

  • Liquid masses above the min horizontal flow, and below the viscosity, initially move more left than right. 

If you want to see some fun things, try any of these in the spread sheet:

  • Use Naptha (MaxMass 740, Viscosity 30, Min Horizontal Flow 10) and paint between 40 and 53.3 kg. Note that what you observe means any time you drop Naptha from a liquid vent, it all flow left. If you drop it on a ledge, then it will never flow right, ever, even without a wall.  If liquid pumps could be rotated, this would be a super cool feature.
  • Any liquid with a high viscosity will have a hard time moving right. 
  • Now see if you can find the exact mass where the left side caps at 30, and then find the mass where the right side caps at 30. Then swap to a different liquid and play some more.  There are a lot of cool patterns here. 
  • Look up the stats on ViscoGel, and convince yourself why it does not move left or right.  At high mass, the stuff does really weird things (another post coming soon). 

I found an error - What can I do?

Please comment below and share.  I have played with Water (so PH20, SaltWater, Brine, and more), Crude, Petro, Magma, Naptha, and Liquid Gold. I've tried to break it, but can't. I'd love to fix any flaws.

Link to comment
Share on other sites

26 minutes ago, Lifegrow said:

Now rest my child, rest your weary head.

But this is just part 1. ;) Yesterday I finally cracked high pressure (like 99999kg) expansion... It's definitely "janky", but completely predictable (and slightly right flowing rather than left...).

28 minutes ago, Lifegrow said:

Dream of correctly flowing rivers and seas where the tides shan't be blocked by 10 grams of exhalation...

But these ONI dreams are so much fun (...takes a boat to get to neighbors on the right, turns around and sails left around the whole world to get there...). 

I also figured out how to create waterfalls without the extra blob of a different liquid, from either side, capture them mid air to avoid splashes, etc.  I'm hoping today to get them to swap liquid type without breaking. so we can sync them up to the disco machine (but I'm not sure this one will work). Wouldn't it be fun to have your waterfalls change color every 10 seconds. :) This is my fun side project between writing up my deep dive into liquids....

Link to comment
Share on other sites

And here I was doing my own tests on viscosity of liquids. This saves me sooooooo much time and effort. 3 cheers for mathmanican!



I was noticing a pattern that liquid was flowing to the left with a predictable amount if over the predefined mass for a single tile of liquid, but I could never figure out the exact equation. Here are the results of my tests. Sometimes weird mechanics would happen and I might just blame that on debug if anything (sublimation). The numbers here are min and max thresholds of one tiles worth of liquid.


30-40g - Bead forms > 10g
Polluted Water
Salt Water
Super Coolant
Carbon Dioxide

300-400g - Rounding Error between 320-330g
Crude Oil









300 + 120 - 400 = 20*.25 = 5 on ground then 20*.75 = 15

(liquid amount + added amount - cap)*.75=on tile
(liquid amount + added amount - cap)*.25=on floor

Here is something fun I created out of stacks of 10g at around 75C from oil, coolant, naptha, petrol, ethanol, sulfur, brine, salt, pw, water, and visco gel in that order.




Link to comment
Share on other sites

20 minutes ago, BLACKBERREST3 said:

And here I was doing my own tests on viscosity of liquids.

I've got at least 2 more posts in this series. One on single high pressure beads (tons of extermely interesting mechanics - found the missing link last night), another on multi-layer flow (still have to completely figure this one out). Then I'll move on to gas flow (aerodynamics), and then fluid interactions....  Or I might sleep. :) 

Link to comment
Share on other sites

Stinky: Mi-Ma, the metal cannon needs to be built on the left of the base, otherwise you'll fry us all to death......  Never forget the 4:9:3 rule... and pay attention to the minimal horizontal flows......

Mi-Ma: What are you talking about. Liquids behave the same on all sides. (Turns on cannon, floods base)

Meep (upon returning from ranching): Where did everyone go? Ooooh, shiny new floors. :) 

Link to comment
Share on other sites


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.

  • Create New...