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.0.3.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.0.3-py3-none-any.whl (9.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: vip_ivp-0.0.3.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.0.3.tar.gz
Algorithm Hash digest
SHA256 0f85715409f6e0b5d1af2d0a08056828c8ac3da005f8501718661cb408ec3ac4
MD5 a3979912d39c0a3d4339f15c1396fcd5
BLAKE2b-256 21f7f2f455a4ee6b682b003a918b99d47042e0ddbeb652e52a8d3d971053f847

See more details on using hashes here.

Provenance

The following attestation bundles were made for vip_ivp-0.0.3.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.0.3-py3-none-any.whl.

File metadata

  • Download URL: vip_ivp-0.0.3-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.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 e165b6ecda5c5361445f4b34ca7687f4f5d52b7278687926f5865d5acf68d4d3
MD5 e51cf8a8654b00b4e65d934a43ac68e2
BLAKE2b-256 f16a53d80980c4cb13fbc907a29f02f8f035a3c74cf98f136f5707d7c78fe1fd

See more details on using hashes here.

Provenance

The following attestation bundles were made for vip_ivp-0.0.3-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