Skip to main content

Solve ODEs without having to build the system of equations.

Project description

vip-ivp

Solve ODEs naturally within the script's flow—no need to manually construct a system of equations.

Minimal example

import vip_ivp as vip

# Exponential decay: dN/dt = - λ * N
d_n = vip.loop_node()
n = vip.integrate(d_n, 1)
d_n.loop_into(-0.5 * n)

# Choose which variables to plot
n.to_plot("Quantity")
d_n.to_plot("Derivative")

# Solve the system. The plot will automatically show.
vip.solve(10, time_step=0.001)

Motivation

The traditional way to solve an Initial Value Problem (IVP) is to define the function $y'=f(t,y(t))$ and pass it into a solver, such as scipy.integrate.solve_ivp().

However, this approach becomes cumbersome and error-prone for complex systems, as both $f$ and $y$ grow in size and complexity. This is why industries rely on tools like Simulink, which provide a more intuitive, graphical approach for handling large IVP systems.

This package brings key abstractions from graphical IVP solvers into a scripting environment, enabling a more natural and modular way to define differential equations:

  • Decouples the solver from the system definition.
  • Builds the system incrementally, following the script’s natural flow.
  • Represents differential equations as loops, improving clarity.
  • Encourages a functional programming paradigm for better system architecture.
  • Seamlessly integrates with the Python ecosystem, working alongside libraries like NumPy and SciPy.

Demo: Mass-spring-damper model

import vip_ivp as vip

# System parameters
m = 300.0  # Mass (kg)
c = 1500  # Damping coefficient (N.s/m)
k = 25000  # Spring stiffness (N/m)
displacement_x0 = 0.2  # Initial value of displacement (m)

# Create simulation
# System equation is: m * acc + c * vel + k * disp = 0 <=> acc = - 1 / m * (c * vel + k * disp)
# We do not have access to velocity and displacement at this stage, so we create a loop node.
acceleration = vip.loop_node()
velocity = vip.integrate(acceleration, 0)
displacement = vip.integrate(velocity, displacement_x0)
# Now we can set the acceleration
acceleration.loop_into(-(c * velocity + k * displacement) / m)

# Choose results to plot
displacement.to_plot("Displacement (m)")
velocity.to_plot("Velocity (m/s)")

# Solve the system
t_simulation = 10  # s
time_step = 0.001
vip.solve(t_simulation, time_step=time_step)

Features

Integrate

Integrate a temporal variable starting from an initial condition.

integrated_var = vip.integrate(source, x0=0)

Handle integration loops

Create loop nodes to handle feedback loops in the system.

loop = vip.loop_node(input_value=0)
loop.loop_into(integrated_var)

Loop nodes are essential to solve ODEs in a "sequential" way.

To solve an ODE, follow these steps:

  1. Create a loop node for the highest-order derivative of the equation:
ddy = vip.loop_node()
  1. Create lower-order derivatives by integration
dy = vip.integrate(ddy, dy0)
y = vip.integrate(dy, y0)
  1. Loop into the equation (In this example: $4 \frac{d^2y}{dt^2} + 3 \frac{dy}{dt} + 2y = 5$):
ddy.loop_into(5 - 1 / 4 * (3 * dy + 2 * y))

Create sources

Create source signals from temporal functions or scalar values.

source = vip.create_source(lambda t: 2 * t)

Solve the system of equations

Solve the system until a specified end time.

vip.solve(t_end=10,
          method="RK45",
          time_step=None,
          t_eval=None,
          plot=True,
          **options)

For **options, see the SciPy documentation.

Plot results

Plot variables with .to_plot(variable_name : str) method.

The plot is automatically created when the system is solved.

def foo():
    variable = vip.create_source(5)
    variable.to_plot("Variable name")


foo()
vip.solve(10)  # 'variable' will be plotted, even if it was declared in a function.

Explore results

Generate an interactive plot from a given function. The plot includes sliders, allowing users to adjust input values dynamically.

This feature requires the sliderplot package:

pip install sliderplot

def mass_spring_damper_system(m=1, c=1, k=1, x0=0.2):
    acceleration = vip.loop_node()
    velocity = vip.integrate(acceleration, 0)
    displacement = vip.integrate(velocity, x0)
    acceleration.loop_into(-(c * velocity + k * displacement) / m)
    return displacement


t_simulation = 50  # seconds
time_step = 0.001  # seconds
vip.explore(mass_spring_damper_system, t_simulation, time_step=time_step, title="Mass-Spring-Damper mechanism")

Advanced features

Save intermediary results

Save variables for later analysis.

Its only use-case is when the variable may be lost due to context, typically for variables that are created inside functions.

def foo():
    variable = vip.create_source(5)
    variable.save("bar")


foo()
bar = vip.get_var("bar")
vip.solve(10)  # 'variable' will be plotted, even if it was declared in a function.

Create a new system

Initialize a new system.

If you want to simulate multiple systems in the same script, use this function. Otherwise, the previous systems will be solved again with the new one, which will be slower.

vip.new_system()

Limitations

  • Temporal variables can only access their values at time $t$.
  • Therefore, there is no function to compute derivatives.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vip_ivp-0.1.0.tar.gz (12.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vip_ivp-0.1.0-py3-none-any.whl (9.4 kB view details)

Uploaded Python 3

File details

Details for the file vip_ivp-0.1.0.tar.gz.

File metadata

  • Download URL: vip_ivp-0.1.0.tar.gz
  • Upload date:
  • Size: 12.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for vip_ivp-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e92a33f7a4f1bf4d077fc502aabc6f311267bfda21b583aeceddab917493ef4e
MD5 3ff6d39f3ce628453c0721899cec480d
BLAKE2b-256 2cda3a1a33944104480af6f86a8b1ab64274873519a3a7abe043db1a70182d68

See more details on using hashes here.

Provenance

The following attestation bundles were made for vip_ivp-0.1.0.tar.gz:

Publisher: python-publish.yml on ngripon/vip-ivp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file vip_ivp-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: vip_ivp-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 9.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for vip_ivp-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6c5f97dbea34cc58a9f37e72d4826c31df96f84e03109002c956d2be64c1251d
MD5 65d560702407d32de1e094186d0bf810
BLAKE2b-256 4a68a5e484817bdd00b0a56ce01cba45a1297f14faae54423da518423eb89ccd

See more details on using hashes here.

Provenance

The following attestation bundles were made for vip_ivp-0.1.0-py3-none-any.whl:

Publisher: python-publish.yml on ngripon/vip-ivp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page