Marketplace › From Ordinate 2D
Energy audit of the open scene
Open any scene, then run it: kinetic and potential energy of every moving body, their sum, and how much was lost.
Use in Ordinate 2DOpens in the Script tab: it runs when you press Run. Free, no account needed.
"""Energy audit of the open scene: where does the energy go?
Open any scene first (an example, or your own), then run this script: it does not clear the scene. Every 0.05 s it adds up
the kinetic energy (½mv² + ½Iω²) and the gravitational potential energy (m g y) of every moving body and records them with
their sum. A sum that stays flat means nothing is lost; a falling sum is friction, inelastic hits and damping at work.
(Energy stored in springs is not counted: a scene with springs shows it as an exchange.)
Runs in the studio (Script tab → Run) and locally: python3 energy_audit.py
"""
import studio as s
EVERY = 0.05 # s between rows
DURATION = 10 # s
next_row = 0.0
start = None
def totals():
g = -s.gravity[1]
ke = pe = 0.0
for b in s.bodies():
if b.static:
continue
ke += 0.5 * b.mass * (b.vx ** 2 + b.vy ** 2) + 0.5 * (b.inertia or 0.0) * b.omega ** 2
pe += b.mass * g * b.y
return ke, pe
moving = [b for b in s.bodies() if not b.static]
if moving:
print(f"Auditing {len(moving)} moving bod{'y' if len(moving) == 1 else 'ies'} for {DURATION} s: a row every {EVERY} s in the Script sheet "
f"(Table tab), the totals here every 2 s.")
else:
print("This scene has no moving bodies. Open a scene first (an example, or build one), then run the audit on it.")
next_print = 0.0
@s.on_step
def audit(t, dt):
global next_row, start, next_print
if t + 1e-9 < next_row:
return
next_row += EVERY
ke, pe = totals()
if start is None:
start = ke + pe
s.record(t=t, KE=ke, PE=pe, E=ke + pe, lost=start - (ke + pe))
if t + 1e-9 >= next_print:
next_print += 2.0
print(f"t = {t:4.1f} s: KE {ke:8.2f} J, PE {pe:8.2f} J, total {ke + pe:8.2f} J")
@s.on_end
def report():
ke, pe = totals()
if start is not None and moving:
lost = start - (ke + pe)
print(f"total energy: {start:.2f} J at the start, {ke + pe:.2f} J now: {lost:.2f} J lost "
f"({100 * lost / start if start else 0:.1f} %) to friction, collisions and damping")
s.run(DURATION)