What the simulation is and how it works?
Particle and grid based simulation
Particles exported by Phoenix FD
What the simulation is and how it works?
All people have an intuitive idea of what a simulation is, because we are doing it every day, trying to predict the future and make decisions. For example if we have to cross a street, we are trying to predict where the cars will be and we do all this automatically without any complicated math.
If you try to predict where a moving car will be after one second, a simple extrapolation is quite useful. The car can't change its speed too much in a second. But if you try to predict the car's position after an hour, the simple extrapolation doesn't work. We can only predict the future position of an object for short time intervals, where the velocity remains relatively the same. The longer the time interval is, the bigger the velocity change is, and the bigger the error of the estimated object position is. However, if we have some rule that allows us to update the velocity (for example we know the road and the speed restrictions), we can extrapolate for a short time interval, then update the velocity, and by repeating the same procedure step by step we can achieve plausible long term predictions.
The fluid simulation works the exact same way. The simulator extrapolates and updates velocity, evaluating new states of the fluid continually. In most fluid simulation systems, the extrapolation phase is called advection, and the velocity update is called pressure projection. For the extrapolation we will use the term advection, but for the velocity update/pressure projection we will use the term conservation, because it is highly related to the fluids ability to keep its amount. The extrapolation time interval mentioned above is called simulation time step. In Phoenix FD the simulation time step is controlled by the Steps Per Frame (SPF) parameter, which is equal to the frame duration divided by the simulation time step.
Particle and grid based simulation
There are two main approaches used in simulation systems:
- The first one is focused on the matter. The mass, the color, the temperature, the coordinates, etc. are just properties of the matter, and are associated to abstract pieces of the matter called particles. This is the concept of the particle based simulators, Phoenix FD uses this concept to calculate foam and splash.
- The second approach is focused on the space. The mass, the color, the coordinates, etc. are just properties of the space, and are associated to abstract pieces of space called voxels or cells. This is the concept of the grid based simulators. Phoenix FD uses this concept to calculate the fluid's behavior. When a Phoenix FD simulator is created, the grid in the viewport is represented as a green box, when it is empty or as a red box when it contains simulated data.
The grids are similar to 3d bitmaps, but the pixels are called voxels or cells. When Phoenix FD simulates, it repeats the same operations for each cell, so the more cells there are, the slower the simulation runs. The result of the simulation is a sequence of files called cache files. Each cache file is similar to multi-channel 3d bitmap, but instead of colors, it contains physical values.
Particles exported by Phoenix FD
Phoenix FD is a grid based simulator, but there are three particle types that Phoenix FD exports - "Foam", "Splashes", and "Simple drag". The particles are exported in separate groups, the first two types have one particle group per type, while the third type is exported in per source groups. The difference between those groups is in the particle birth and simulation methods they use.
The birth of the particles can be performed automatically (for foam and splashes), by user source (see the PHXSource), or by script. When automatic birth is used, the simulator calculates a "birth potential" for each cell and compares this potential with the birth threshold set by the user. If the potential is above the threshold, the simulator creates new particles with quantity specified in the "birth rate" parameter, in thousands per cubic scene unit. Both foam and splashes are born this way; the only difference is how the "birth potential" is calculated. Additionally, when a splash particle hits the water surface, foam is automatically created.
The simulation of the particles is very different for each type. The simplest one is the "Simple drag". These type of particles are just dragged with the fluid, like the PF operator PhoenixFD Force, but it is much more efficient. You can drag millions of particles in just a few minutes. The second type by complexity is the splashes type. The splashes are just left in free fall until they hit an object or the water surface. The free fall is not the simplest one, it is affected by the movement of the air (do not forget that Phoenix FD simulates the air too, not just the liquid!) and the air-splashes interaction is controlled by the air friction parameter. The most complicated type is foam. Foam particles interact not only with the fluid, but with each other as well. This interaction produces a repulsive force when the particles are too close, and an attractive force, ensuring the foam consolidation. This process is the most expensive one and is controlled by the "Volume cycles" parameter. When only surface foam is needed, the aforementioned process can be switched off by setting the parameter to zero.
Threads limit (MXS: maxthreads) - allows you to specify an upper limit for the number of threads used for the simulation. When the value is set to "0" the maximum number of threads (cores) will be used.
Numa nodes - if your simulation is executed over a NUMA machine, you can specify which nodes to be used. Phoenix FD is very sensitive to the memory transfer and if all the nodes are used the result may be decreased performance caused by the low bandwidth between the different nodes.
Start frame (MXS: startframe) - start frame of the simulation.
Stop frame (MXS: stopframe) - end frame of the simulation.
Use script (MXS: script, use_script) - enables using MAXScript during the simulation.
Object voxels(MXS: objvox) - each solid object is represented in the grid as voxels. This options chooses how to proceed when given voxel intersects the object's surface i.e. is in the object. It does not produce significant change in the simulation, but is of crucial importance for the rendering. For example, if the object voxels are circumscribed, the liquids can't reach the real objects surface and this is visible in the rendering. This option has a per object form, you have to define a user defined property with name PHX_Voxels. The corresponding values are 0 - circumscribed, 1- center, 2 - inscribed.
Circumscribed - all voxels that intersect the surface are considered solid. It's recommended for fire simulations.
Center - the surface voxels are considered solid only if their bigger part lies in the object.
Inscribed - all voxels that have intersection with the surface are considered non solid. It's recommended for liquid simulations.
Inscribed object voxels Circumscribed object voxels
As we already said in the introduction, the conservation process is responsible for the velocities update, thus allowing us to make the next short term extrapolation, or advection as we will call it below. But one may ask why we need to control it and dig into details, isn't it possible to just do it, leaving the user in happy ignorance? Well, the first reason is that we have to choose between speed and quality. The second reason is that the conservation methods are not ideal, they have their specific issues, and you have to decide which one to use knowing the advantages and disadvantages.
Few words how the conservation works. In general, the conservation aspires to equalize the ingoing and outgoing flows in each cell. This sounds easy, why not just calculate the flow balance and distribute the compensation equally among all the six walls of the cell? Well, that sounds great, but when we balance one cell and go to balance the next cell, we will destroy the balance of the first one, because the cells share a wall, and when we change the flow of this wall in order to balance the second cell, we destroy the balance of the first one. All this seems like trying to remove an air bubble under a wall paper. Well, here comes the complicated math that solves the problem in a magical way. One thing that is important to know is that the mass distribution of the fluid plays important role in this process. Imagine a jet of oil colliding with a jet of water. It's quite obvious that the result will not be the same as if the jets are equally weighted. Not so obvious, but also observable is when we simulate fire - the hot air is lighter than the cold one and this changes the flame shape.
Method (MXS: refltype) - choose between different methods for evaluating the conservation.
Symmetric - this method is suitable for simulations which require a high degree of symmetry e.g. a nuclear mushroom. Its main disadvantage is that it may produce chess-like pattern in the velocity and this is clearly visible in the velocity channel. In most production cases, however, the velocity is not visualized, but the smoke or the temperature is, so don't be afraid to use it.
Smooth - the smooth and the symmetric methods are actually the same, but they differ by the velocity notation. The smooth method considers it defined over the left/down walls, and the symmetric method considers it defined in the center of the cell. This difference allows the smooth method to produce a smooth velocity field, however the result is not symmetric.
Buffered - this method is different from the smooth and symmetric methods, and technically its conservation is much worse compared to them, but from an artistic point of view sometimes is better, because it produces small details. Buffered can't be used for liquids or for any simulation where the conservation quality is important.
|Smoke simulated with symmetric type of conservation||Smoke Simulated with smooth type of conservation||Smoke simulation with buffered type of conservation|
Quality (MXS: reflprec) - In most simulations this parameter does not have significant impact, but in some cases it plays important role. As the name suggests, the conservation phase is highly related to the ability of the fluid to keep its amount. The animation below demonstrates how this matters. A smoke source is placed in an almost closed room, where the only exit is near the floor. In the real world the smoke will fill the room and then reach the exit, just because once created the smoke is accumulated and does not disappear. However, when the conservation parameter is low, the smoke does not keep its amount and disappears, never reaching the hole.
Note that the smoke reaches the hole with conservation at about 200, and this value is not accidental. The vertical size of the grid is 100, and if it was smaller, the conservation value that allows the smoke to reach the hole would have been smaller too. You can think of this parameter as a distance scope in which the conservation spreads the velocity influence. One may ask - well, if this is the scope of the conservation, does that mean that we are unable to simulate liquids with conservation less than the liquid depth? It sounds logical, because the bottom of the container has to "tell" the surface that there is a support beneath. Yes, this would be true if the liquids were simulated without any boost of the conservation, but it is not. That's why the liquids can be hold in a container with conservation of 10 when the depth is more than 100.
Uniform density (MXS: uniform_mass) - This option controls whether or not the mass of the fluid is considered during the simulation. The mass is considered when this box is not checked. For liquids simulations keep it off. Fire simulations work better with this option off, however it may be useful for pure smoke simulations or explosions.
Material transfer (Advection)
As we already said in the introduction, the advection is the short term of extrapolating the grid's content. For the particle based simulators the advection is very simple and intuitive, you just have to add the velocity to the particle's coordinates, multiplied by the time step. However, for the grid based simulators the advection is much more complicated. Imagine a simple bitmap containing a moving car, you know the velocity of the car and have to create an image of the same car after one second. The simulator's advection has the exact same task. Sounds easy, right? However, there are two major problems: what we have to draw in the old position of the car, and what we shall do if the car's movement is not an integer count of pixels, which is the usual situation. There are different solutions, but all of them involve interpolation and therefore blur the content. This is one of the most important disadvantages of the grid advection, and to minimize the blur it is recommended to keep the SPF as low as possible.
Method (MXS: advtype) - specifies the algorithm used for calculating the advection
Classic(Semi-Lagrangian) - this is the most commonly used algorithm for advection. Has good stability , the only method that can achieve settled liquids, but does not strictly conserve the quantity of the transferred material.
Slow moving - this method is a modification of the Semi-Lagrangian method optimized for slow moving fluids and preventing the numerical dissipation.
Forward transfer - good conservation abilities, but less stability compared to the classic method. Tends to produce cross-like artifacts and underwater cavities when used with liquids.
Multi-pass - this less dissipative method, produces more fine details and keeps the smoke interface sharper compared to other methods, recommended for large scale explosions, veil-like smoke, pyroclastic flows, and all other situations where the sharpness is important.
Steps per frame (SPF) (MXS: spflimit0) - with this parameter we set the simulation time step to a good enough value for plausible extrapolation. Because the time step parameter is confusing for most users, we now set the simulation steps per frame instead. This parameter is very important and is closely related to the simulation's dynamics. When the simulation moves quickly, you have to use higher SPF, otherwise the result tends to form artifacts like grainy appearance, flickering liquid surface, etc. Higher SPF decreases the performance in a linear way, i.e. if you increase the SPF twice, your simulation will go twice as slow. However, the quality does not have linear relation to the SPF. Each simulation step kills fine details, and thus you have to use the lowest possible SPF that hides the above mentioned artifacts. Phoenix FD supports non integer SPF and SPF below 1, but It's recommended to use an integer value when possible. Values below 1 are needed when the simulation is very slow.
(MXS: A_StartSim, A_StopSim) - start, pause and stop the simulation.
- if the velocity channel is exported, Phoenix FD is able to restore the simulation. This command finds the nearest file containing velocity channel and continues the simulation from there (see Backup interval parameter).
Load (MXS:A_StartSim) - loads the content of a chosen cache file as initial state for the simulation.