I am currently facing some difficulties in the design of an algorithm and hope that programmers have some ideas. I am not asking for code contribution, only for ideas.
The scenario is brake pipe pressure propagation. In openBVE, each car has a single variable that stores the current pressure of the brake pipe. For your information: The brake pipe is a pipe running from the very first car to the very last car of the train. For sake of simplicity, we can assume that the volume inside the brake pipe remains constant throughout the simulation, and also its surface area. In the case that there is a pressure rise or drop on some car, we want the pressure to propagate over time until an equilibrium is reached, meaning until all cars have the same pressure in the brake pipe. Of course in reality, the brake pipe is a continuous entity, while in the simulation, we simply simulate one point of the brake pipe per car.
An algorithm that does pressure propagation needs to follow these rules: A time difference is given (in seconds) that corresponds to the difference since the last execution of the algorithm. Additionally, the distance between each car is known (in meters) and needs to be incorporated. The algorithm needs to make sure that the average pressure in the brake pipe remains constant after one iteration, meaning it is not allowed to add or subtract pressure overall, only to more equally distribute it along the cars. There can be any kind of flow rate constant, but is not allowed to be infinite.
I am asking for ideas because my previous implementation are flawed. I will present a simple not working algorithm that does not even meet the above criteria just to show what such issues can be.
1) Mean algorithm between cars
For each car, calculate the arithmetic mean of its own pressure (X) and those of the adjacent cars (A and B), i.e. (A+X+B)/3. For the end cars, use the form (A+X+X)/3 instead. One can show that the total pressure in the train, e.g. for three cars: (A+A+B)/3 + (A+B+C)/3 + (B+C+C)/3 is equal to A+B+C, so at least the total pressure remains constant. This showcase scenerio does not include time or distance though, and one might expect that with high frame rates, it converges extremely fast. However, this is absolutely not the case. The reason is probably related to the fact that if car A has some pressure and all the others have 0, after one iteration, car B will have a pressure of A/3; in the next iteration, car C will have a pressure of B/3 = A/9 and so forth. So convergence is - don't know how to phrase it - maybe logarithmically (or exponentially with a negative exponent?) Either way, regardless of how you call it, it is extremely slow.
2) Current openBVE algorithm between cars
We have a flow rate measured in Pa*m/s (pressure * length / time), which is a constant. For each car, the up to two adjacent cars are compared. If the current car has a higher pressure than any of the adjacent cars, we first calculate the pressure difference D (in pascal) to the respective car. Then, we multiply the flow rate constant (Pa*m/s) by the time difference (s) and divide by the length between the cars (m) to arrive at the maximum pressure P (Pa) that can be exchanged in the current iteration. If P>D, we limit P to D. If P > current brake pipe pressure in this car, then we further limit P to that value. The brake pipe pressure in the current car is then reduced by P/2 and that of the adjacent car increased by P/2. Note that "new pressure" and "old pressure" are separated, so all of the calculations query the old values and derive new values to be applied simulaneously. The exchange is P/2 for two reasons: First, it ensures that in the next generation, the other car will not exchange the same amount of pressure back to this car, and second, that if pressure is exchanged between both adjacent cars, only half the current pressure can be exchanged to either one. Unfortunately, while this algorithm implements both the time and distance constraints, it suffers from the same logarithmic (?) rate of conversion, thus the anticipated flow rate is not actually achieved. I am currently using a value of 1,000,000,000 Pa*m/s, meaning that theoretically, given a maximum pressure difference in the brake pipe of 500,000 Pa (500 kPa) and a total length of the train of 300 m, it should only take 0.15 s to propagate a particle from one end of the train to the other, but an equilibrium only forms in 2-5 minutes in openBVE's reality.
3) Instantaneous distribution over all cars
In order to eliminate the convergence problem, I recently experimented with the following idea. If we continue to measure flow rate in Pa*m/s (pressure * distance / time), then given a constant, one can rearrange the formula Constant=Pressure*Length/Time to Pressure=Constant*Time/Length, corresponding to the pressure that could be exchanged over a given distance in a given time. If we, for every car A, calculate for every other car B the value Pressure=Constant*Time/Length, where Length is the total length from car A to car B, then we have the pressure that could be exchanged between cars A and B under the time and distance constraints. What I did was for car A to create an array B[] with all those pressure values. Of course, if we sum up all the pressure values in B[], we might exceed the pressure currently available in car A. So what I did was to normalize B[] so that the total pressure in B[] would be the same as in A. Now, we simply transfer all pressure of A to all other cars B given the weights in B[]. This means that every car will transfer its own pressure to all of the others. One issue is that as the distance between A and A is zero, one cannot meaningfully include A itself in B[], so I left A in B[] at 0. Interestingly, this algorithm converges perfectly quick. But there is conceptual problem: Once an equilibrium forms, one might expect all cars to have the same pressure. Not with this algorithm: The center car will have a peak pressure and the outer cars the lowest pressure. That is the equilibrium. The algorithm further has the problem that it does not prevent a car from having more pressure available than is possible.
As such, if you have ideas how one could implement a pressure/flow/propagation algorithm with the constaints of including time, length and some flow constant (whatever unit), I am open for these ideas. Things that might help conceptually: We can assume that the surface area and volume of the brake pipe is constant. As pressure is Mass * Acceleration / Area, and the area is constant, it can be accounted for in the flow constant and is otherwise irrelevant. Furthermore, unless one includes the acceleration due to gravity in the algorithm, Acceleration is also constant and thus irrelevant, thus for the purpose of the simulation, Pressure behaves the same as Mass, meaning one can visualize the propagation as exchange of mass or particles instead of thinking in pressure.
If you are interested in looking at the revelant parts of the source code: The file is TrainManager.cs and the procedure is called "private static void UpdateBrakeSystem(ref Train Train, double TimeElapsed, out double[] DecelerationDueToBrake, out double[] DecelerationDueToMotor)", and the relevant code starts with the comment "// propagation" and ends at the comment "// apply". There are other things in that source such as brake pipe leaks, which are irrelevant here.

