I play with CodeWorld and use the "entrypoint" activityOf() to simulate a physical system consisting of tanks. Here we have one tank with an outlet flow qout(h) that depends on the height of volume level. Of course, for serious simulation work one should use other software, but still fun to do here!
program = activityOf(initial, change, tank_water)
composedOf = pictures
-- Initial value and parameter
initial(rs) = 5
g = 9.81
area = 0.015
-- Inlet flow
qin = 0.0
-- Dynamics using Euler approximation
qout(h) = area*sqrt(2*g*max(h,0))
change(h, TimePassing(dt)) = max(h,0) - qout(h)*dt + qin*dt
change(h, other) = h
-- Animation of system
tank_water(h) = composedOf [tank, water(h), graph, coordinatePlane]
tank = translated(thickRectangle(width,height,0.2),position,4)
width = 3
height = 8
position = -5
water(h) = translated(colored(solidPolygon [(-width/2, 0), (-width/2, h), (width/2, h), (width/2,0)],
light(blue)),position,0)
-- Graph of evolution of h(t) - here used monitored values and about 5 seconds between each data point
graph = polyline [(0,5), (1,3.7), (2,2.3), (3,1.3), (4,0.7), (5,0.2), (6, 0)]
For educational purpose I think it is good to combine an animation with a graph in a diagram that shows how the height develops over time. Here I entered in the code a "fake" graph since it was easy to measure up (and I could also enter the analytical solution to make the graph adapt to parameters).
I wonder how one can include a subsystem that collect data from the animation and present it in the graph as the simulation proceed. Any ideas?
One cumbersome idea I think of is to extend the model state that include the measured points to be collected during the simulation. We can beforehand say that we collect 10 samples of h and t with a time distance of say 5 seconds and we expand the graph as the data comes in.
Another idea is to somehow "add-on" some general data logger to the activityOf()-program that store data on a file that you afterwards can study with any software. Perhaps such a logger is already available in the Haskell-environment?
But I am very uncertain of how to do this and here are perhaps some better and more general way to do it?
I made a solution "the cumbersome" way. Wish I could structure it better from the input I have got. Appreciate suggestions for improvements so that the code could be shorter. I feel clumsy with tuple-handling. Further creation of the table and later graph could be more separated from the tank-process. That would facilitate re-use to other simulation tasks in CodeWorld. Improvements welcome!
--
I have now updated the code and made it shorter but also added more data points in the table. The state_and_table must be a tuple in CodeWorld and handling of tuples not possible with an index. Further, you can now change the pump rate qin with arrows up and down.
Expand to two tanks (or more) make it more of a challenge to control the water height and leave that as an exercise to you! Enjoy!
Link to run https://code.world/#P2uQaw2KBSbyspnQSn5E4Gw