CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pysd

System Dynamics modeling library for Python that integrates with data science tools

Pending
Overview
Eval results
Files

functions-module.mddocs/

Mathematical and Utility Functions

PySD's functions module provides a comprehensive set of mathematical and utility functions equivalent to Vensim/XMILE built-ins, enabling System Dynamics models to perform complex calculations and logic operations.

Capabilities

Mathematical Functions

Core mathematical operations with special handling for System Dynamics modeling requirements.

def if_then_else(condition, val_if_true, val_if_false):
    """
    Conditional logic implementation.
    
    Parameters:
    - condition: bool or array - Conditional expression
    - val_if_true: scalar or array - Value when condition is True
    - val_if_false: scalar or array - Value when condition is False
    
    Returns:
        scalar or array: Selected value based on condition
    """

def xidz(numerator, denominator, x):
    """
    Division with specified result for 0/0.
    
    Parameters:
    - numerator: scalar or array - Numerator value
    - denominator: scalar or array - Denominator value  
    - x: scalar or array - Value returned when both numerator and denominator are 0
    
    Returns:
        scalar or array: Division result or x for 0/0 case
    """

def zidz(numerator, denominator):
    """
    Division returning 0 for 0/0.
    
    Parameters:
    - numerator: scalar or array - Numerator value
    - denominator: scalar or array - Denominator value
    
    Returns:
        scalar or array: Division result or 0 for 0/0 case
    """

def integer(x):
    """
    Integer truncation.
    
    Parameters:
    - x: scalar or array - Input value
    
    Returns:
        int or array: Truncated integer value
    """

def quantum(a, b):
    """
    Quantum function - rounds a to nearest multiple of b.
    
    Parameters:
    - a: scalar or array - Value to round
    - b: scalar or array - Multiple to round to
    
    Returns:
        scalar or array: Rounded value
    """

def modulo(x, m):
    """
    Modulo operation.
    
    Parameters:
    - x: scalar or array - Input value
    - m: scalar or array - Modulo divisor
    
    Returns:
        scalar or array: Remainder after division
    """

Usage Examples

from pysd import functions

# Conditional logic
temperature = 25
comfort_level = functions.if_then_else(
    temperature > 20,
    "comfortable", 
    "cold"
)

# Safe division avoiding division by zero
growth_rate = functions.xidz(
    new_population - old_population,
    old_population,
    0  # Return 0 if both are 0
)

# Integer operations
whole_units = functions.integer(3.7)  # Returns 3

Time Functions

Functions for time-based calculations and temporal patterns.

def ramp(time, slope, start, finish=None):
    """
    Ramp function over time.
    
    Parameters:
    - time: scalar or array - Current time value
    - slope: scalar - Rate of increase per time unit
    - start: scalar - Time when ramp begins
    - finish: scalar or None - Time when ramp ends (None for no end)
    
    Returns:
        scalar or array: Ramp value at given time
    """

def step(time, value, tstep):
    """
    Step function at specified time.
    
    Parameters:
    - time: scalar or array - Current time value
    - value: scalar - Step height
    - tstep: scalar - Time when step occurs
    
    Returns:
        scalar or array: 0 before tstep, value at and after tstep
    """

def pulse(time, start, repeat_time=0, width=None, magnitude=None, end=None):
    """
    Pulse and pulse train functions.
    
    Parameters:
    - time: scalar or array - Current time value
    - start: scalar - Time when first pulse begins
    - repeat_time: scalar - Time between pulses (0 for single pulse)
    - width: scalar or None - Pulse duration (default: time step)
    - magnitude: scalar or None - Pulse height (default: 1/time_step)
    - end: scalar or None - Final time of the pulse (None for no end)
    
    Returns:
        scalar or array: Pulse value at given time
    """

def get_time_value(time, relativeto, offset, measure):
    """
    Extract time values with offsets.
    
    Parameters:
    - time: scalar - Current time
    - relativeto: str - Reference point ("start", "end")
    - offset: scalar - Time offset from reference
    - measure: str - Time unit ("years", "months", "days", "hours", "minutes", "seconds")
    
    Returns:
        scalar: Calculated time value
    """

Usage Examples

# Create time-based patterns
current_time = 15

# Gradual increase starting at time 10
production_ramp = functions.ramp(current_time, slope=2, start=10)

# Policy change at time 20
policy_effect = functions.step(current_time, value=100, tstep=20)

# Periodic maintenance every 12 time units
maintenance = functions.pulse(current_time, start=0, repeat_time=12, width=1)

Array Functions

Operations on multi-dimensional arrays and subscripted variables.

def sum(x, dim=None):
    """
    Sum along specified dimensions.
    
    Parameters:
    - x: array - Input array
    - dim: str or list or None - Dimensions to sum over (None for all)
    
    Returns:
        scalar or array: Sum result
    """

def prod(x, dim=None):
    """
    Product along dimensions.
    
    Parameters:
    - x: array - Input array
    - dim: str or list or None - Dimensions to multiply over
    
    Returns:
        scalar or array: Product result
    """

def vmin(x, dim=None):
    """
    Minimum along dimensions.
    
    Parameters:
    - x: array - Input array
    - dim: str or list or None - Dimensions to find minimum over
    
    Returns:
        scalar or array: Minimum value
    """

def vmax(x, dim=None):
    """
    Maximum along dimensions.
    
    Parameters:
    - x: array - Input array
    - dim: str or list or None - Dimensions to find maximum over
    
    Returns:
        scalar or array: Maximum value
    """

def invert_matrix(mat):
    """
    Matrix inversion.
    
    Parameters:
    - mat: 2D array - Input matrix
    
    Returns:
        2D array: Inverted matrix
        
    Raises:
        LinAlgError: If matrix is singular
    """

Usage Examples

import numpy as np

# Array operations on subscripted variables
population_by_region = np.array([1000, 1500, 800, 1200])

# Total population across all regions
total_pop = functions.sum(population_by_region)

# Find region with maximum population  
max_pop = functions.vmax(population_by_region)

# Matrix operations for economic modeling
input_output_matrix = np.array([[0.2, 0.3], [0.4, 0.1]])
inverse_matrix = functions.invert_matrix(input_output_matrix)

Vector Operations

Specialized functions for vector manipulation and analysis.

def vector_select(selection_array, expression_array, dim, missing_vals, numerical_action, error_action):
    """
    Vector selection operations implementing Vensim's VECTOR SELECT function.
    
    Parameters:
    - selection_array: xarray.DataArray - Selection array with zeros and non-zero values
    - expression_array: xarray.DataArray - Expression that elements are selected from
    - dim: list - Dimensions to apply the function over
    - missing_vals: float - Value to use when there are only zeroes in selection array
    - numerical_action: int - Action to take (0=sum, 1=product, 2=min, 3=max)
    - error_action: int - Error handling action
    
    Returns:
        xarray.DataArray: Selected vector elements based on selection criteria
    """

def vector_sort_order(vector, direction=1):
    """
    Vector sorting indices.
    
    Parameters:
    - vector: array - Input vector
    - direction: int - Sort direction (1 for ascending, -1 for descending)
    
    Returns:
        array: Indices that would sort the vector
    """

def vector_reorder(vector, svector):
    """
    Vector reordering based on sort indices.
    
    Parameters:
    - vector: array - Vector to reorder
    - svector: array - Sort indices
    
    Returns:
        array: Reordered vector
    """

def vector_rank(vector, direction=1):
    """
    Vector ranking.
    
    Parameters:
    - vector: array - Input vector
    - direction: int - Ranking direction (1 for ascending, -1 for descending)
    
    Returns:
        array: Rank of each element (1-based)
    """

Usage Examples

# Vector analysis
sales_data = np.array([150, 200, 120, 180, 220])

# Get sorting order
sort_indices = functions.vector_sort_order(sales_data, direction=-1)  # Descending

# Reorder vector
sorted_sales = functions.vector_reorder(sales_data, sort_indices)

# Get rankings
sales_ranks = functions.vector_rank(sales_data, direction=-1)
print(f"Sales rankings: {sales_ranks}")

Utility Functions

Helper functions for model development and debugging.

def active_initial(stage, expr, init_val):
    """
    Active initial value handling.
    
    Parameters:
    - stage: str - Initialization stage
    - expr: callable - Expression to evaluate
    - init_val: scalar - Initial value
    
    Returns:
        scalar: Appropriate value based on stage
    """

def incomplete(*args):
    """
    Placeholder for incomplete functions.
    
    Parameters:
    - *args: Any arguments
    
    Returns:
        float: Returns 0.0
        
    Note:
        Used as placeholder during model development
    """

def not_implemented_function(*args):
    """
    Placeholder for unimplemented functions.
    
    Parameters:
    - *args: Any arguments
    
    Raises:
        NotImplementedError: Always raises this error
        
    Note:
        Used to mark functions that need implementation
    """

Function Usage in Models

These functions are automatically available within translated System Dynamics models and can also be used directly:

import pysd
from pysd import functions

# Load model that uses these functions internally
model = pysd.read_vensim('complex_model.mdl')

# Functions are used automatically during simulation
results = model.run()

# Can also use functions directly for custom calculations
custom_result = functions.if_then_else(
    results['Population'].iloc[-1] > 10000,
    "High population",
    "Low population"
)

Error Handling

Functions include appropriate error handling for System Dynamics contexts:

  • Division by zero returns appropriate defaults or specified values
  • Array dimension mismatches are handled gracefully
  • Missing values are managed according to SD conventions
# Safe operations that won't crash simulations
safe_ratio = functions.zidz(numerator, 0)  # Returns 0 instead of error
conditional_value = functions.if_then_else(
    denominator != 0,
    numerator / denominator,
    0
)

Install with Tessl CLI

npx tessl i tessl/pypi-pysd

docs

cli-tools.md

external-data.md

functions-module.md

index.md

model-loading.md

model-simulation.md

parameter-management.md

stateful-components.md

utils-module.md

tile.json