A library for running feems simulation
Project description
RunFeemsSim - FEEMS Simulation Runner
RunFeemsSim provides a high-level interface for running FEEMS simulations with automated power management. It simplifies time-series simulation, includes Power Management System (PMS) logic for automatic genset control, and integrates seamlessly with the FEEMS ecosystem.
Features
๐ฏ High-Level Simulation Interface
- Simple API: Run complex simulations with minimal code
- Time-Series Support: Handle operational profiles over time
- Automatic Power Balance: Continuous load balancing across time points
- Result Aggregation: Comprehensive metrics collection
๐ Power Management System (PMS)
- Load-Dependent Control: Automatic genset start/stop based on load
- Multiple Strategies: Configurable PMS algorithms
- Efficiency Optimization: Minimize fuel consumption
- Blackout Prevention: Ensure sufficient spinning reserve
๐ Results Analysis
- Fuel Consumption: Total and per-component fuel usage
- Emissions: CO2, NOx with FuelEU Maritime support
- Energy Breakdown: Propulsion vs. auxiliary energy
- Operating Hours: Runtime tracking for maintenance planning
๐ Pure Python Development
- Clean Python Modules: Standard Python package structure
- Easy to Understand: Straightforward code organization
- Simple to Extend: Add new features easily
- Type Hints: Full type annotation support
Installation
From PyPI
pip install RunFeemsSim
This will install RunFeemsSim along with its dependencies (feems, MachSysS).
From Source (Developers)
# Clone repository
git clone https://github.com/SINTEF/FEEMS.git
cd FEEMS
# Install with uv (recommended)
uv sync
# Or with pip
pip install -e RunFEEMSSim/
Quick Start
Basic Simulation
import numpy as np
import pandas as pd
from RunFeemsSim.machinery_calculation import MachineryCalculation
from feems.system_model import ElectricPowerSystem
from feems.fuel import FuelSpecifiedBy
# Create or load a FEEMS system
system = ElectricPowerSystem(...)
# Initialize machinery calculation
machinery_calc = MachineryCalculation(system)
# Define propulsion power time series
n_points = 1000
time_step_s = 1.0
propulsion_power = pd.DataFrame({
'Propulsion Drive 1': 400 + 200 * np.random.random(n_points),
'Propulsion Drive 2': 300 + 150 * np.random.random(n_points)
}, index=np.arange(0, n_points * time_step_s, time_step_s))
# Define auxiliary power
auxiliary_power = 100 + 50 * np.random.random(n_points)
# Run simulation
result = machinery_calc.calculate_machinery_system_output_from_propulsion_power_time_series(
propulsion_power=propulsion_power,
auxiliary_power_kw=auxiliary_power,
fuel_specified_by=FuelSpecifiedBy.FUEL_EU_MARITIME
)
# Access results
print(f"Total fuel: {result.multi_fuel_consumption_total_kg.fuels[0].mass_or_mass_fraction:.2f} kg")
print(f"Total CO2: {result.co2_emission_total_kg.tank_to_wake_kg_or_gco2eq_per_gfuel:.2f} kg")
print(f"Genset hours: {result.running_hours_genset_total_hr:.2f} hr")
With Power Management System
from RunFeemsSim.pms_basic import PMSBasic
# Create PMS with load-dependent genset control
pms = PMSBasic(
load_threshold_start=0.75, # Start additional genset at 75% load
load_threshold_stop=0.40, # Stop genset when load drops below 40%
min_gensets_running=1 # Always keep at least 1 genset running
)
# Attach PMS to system
machinery_calc = MachineryCalculation(system, pms=pms)
# Run simulation with automatic genset management
result = machinery_calc.calculate_machinery_system_output_from_propulsion_power_time_series(
propulsion_power=propulsion_power,
auxiliary_power_kw=auxiliary_power,
fuel_specified_by=FuelSpecifiedBy.FUEL_EU_MARITIME
)
# PMS automatically starts/stops gensets based on load
print(f"Genset start events: {pms.n_starts}")
print(f"Genset stop events: {pms.n_stops}")
Core Components
MachineryCalculation
Main class for running simulations.
class MachineryCalculation:
"""High-level interface for FEEMS simulations."""
def __init__(self, system: ElectricPowerSystem, pms: Optional[PMS] = None):
"""
Initialize machinery calculation.
Args:
system: FEEMS ElectricPowerSystem
pms: Optional Power Management System
"""
...
def calculate_machinery_system_output_from_propulsion_power_time_series(
self,
propulsion_power: pd.DataFrame,
auxiliary_power_kw: np.ndarray,
fuel_specified_by: FuelSpecifiedBy = FuelSpecifiedBy.IMO,
integration_method: IntegrationMethod = IntegrationMethod.simpson,
time_interval_s: float = 1.0
) -> ElectricSystemRunResult:
"""
Run simulation from propulsion power time series.
Args:
propulsion_power: DataFrame with propulsion drive powers
Index: time in seconds
Columns: drive names
Values: power in kW
auxiliary_power_kw: Auxiliary load time series (kW)
fuel_specified_by: Emission calculation method
integration_method: Time integration method
time_interval_s: Time step in seconds
Returns:
ElectricSystemRunResult with comprehensive metrics
"""
...
PMSBasic
Basic load-dependent Power Management System.
class PMSBasic:
"""
Basic PMS with load-dependent genset start/stop.
Starts additional gensets when load exceeds threshold.
Stops gensets when load drops below threshold.
Maintains minimum number of running gensets.
"""
def __init__(
self,
load_threshold_start: float = 0.85,
load_threshold_stop: float = 0.40,
min_gensets_running: int = 1,
spinning_reserve: float = 0.20
):
"""
Initialize PMS.
Args:
load_threshold_start: Start genset when load > this (0-1)
load_threshold_stop: Stop genset when load < this (0-1)
min_gensets_running: Minimum gensets to keep running
spinning_reserve: Required spare capacity (0-1)
"""
...
def determine_genset_status(
self,
current_load_kw: float,
available_gensets: List[Genset],
current_status: np.ndarray
) -> np.ndarray:
"""
Determine which gensets should be running.
Args:
current_load_kw: Total system load
available_gensets: List of all gensets
current_status: Current on/off status
Returns:
Updated status array
"""
...
Power Management Strategies
Strategy 1: Load-Dependent Control
Automatically start/stop gensets based on load:
pms = PMSBasic(
load_threshold_start=0.80, # Start at 80% of running capacity
load_threshold_stop=0.35, # Stop when below 35% of capacity
min_gensets_running=1 # Always keep 1 running
)
Behavior:
- Load increases โ Start additional gensets when threshold exceeded
- Load decreases โ Stop gensets when load drops
- Prevents frequent switching with hysteresis
- Maintains spinning reserve
Strategy 2: Time-Based Control
Control gensets based on time of day or operational mode:
# Define mode schedule
mode_schedule = pd.DataFrame({
'time': [0, 21600, 43200, 64800], # 0h, 6h, 12h, 18h
'mode': ['port', 'transit', 'transit', 'port']
})
# Different genset configurations per mode
genset_config = {
'port': [True, False, False], # 1 genset
'transit': [True, True, False], # 2 gensets
'maneuvering': [True, True, True] # 3 gensets
}
Strategy 3: Efficiency Optimization
Run gensets at optimal load points:
pms = PMSBasic(
load_threshold_start=0.75, # Target 75% load on running gensets
load_threshold_stop=0.40,
min_gensets_running=1
)
Benefits:
- Operates gensets in efficient range (70-85%)
- Minimizes fuel consumption
- Reduces emissions
Development Workflow
RunFeemsSim follows standard Python development practices.
Package Structure
RunFEEMSSim/
โโโ RunFeemsSim/
โ โโโ __init__.py
โ โโโ machinery_calculation.py # Core simulation logic
โ โโโ pms_basic.py # Power Management System
โ โโโ utils.py # Utility functions
โโโ tests/
โ โโโ test_machinery_calculation.py
โ โโโ test_pms_basic.py
โโโ README.md
โโโ pyproject.toml
Development Cycle
-
Edit Python Files: Make changes directly in
.pyfiles# Edit source files in your preferred editor/IDE vim RunFeemsSim/machinery_calculation.py
-
Run Tests: Test your changes
uv run pytest RunFEEMSSim/tests/
-
Lint and Format: Ensure code quality
uv run ruff check RunFEEMSSim/ uv run ruff format RunFEEMSSim/
-
Type Check: Validate type hints (optional)
uv run mypy RunFeemsSim/
-
Build: Create distribution packages
cd RunFEEMSSim uv build
Why Pure Python?
- Simplicity: Standard Python package structure everyone knows
- IDE Support: Full autocomplete, refactoring, and debugging
- Type Safety: Use mypy and type hints effectively
- Flexibility: Easy integration with any Python tooling
- Transparency: Source code is exactly what gets executed
Use Cases
1. Route Planning
Estimate fuel consumption for planned voyages:
# Load route profile
route_profile = pd.read_csv('route_profile.csv') # time, speed, power
# Run simulation
machinery_calc = MachineryCalculation(system)
result = machinery_calc.calculate_machinery_system_output_from_propulsion_power_time_series(
propulsion_power=route_profile[['power']],
auxiliary_power_kw=route_profile['aux_power'].values
)
# Estimate fuel for voyage
fuel_kg = result.multi_fuel_consumption_total_kg.fuels[0].mass_or_mass_fraction
distance_nm = route_profile['distance'].sum()
fuel_per_nm = fuel_kg / distance_nm
2. Emissions Reporting
Generate IMO/EU compliance reports:
# Annual operation
annual_result = machinery_calc.calculate_machinery_system_output_from_propulsion_power_time_series(
propulsion_power=annual_profile,
auxiliary_power_kw=annual_aux,
fuel_specified_by=FuelSpecifiedBy.FUEL_EU_MARITIME
)
# FuelEU Maritime compliance
well_to_wake_co2 = annual_result.co2_emission_total_kg.well_to_wake_kg_or_gco2eq_per_gfuel
energy_consumed = annual_result.energy_consumption_propulsion_total_mj
ghg_intensity = well_to_wake_co2 / (energy_consumed / 1000) # gCO2eq/MJ
print(f"GHG Intensity: {ghg_intensity:.2f} gCO2eq/MJ")
3. System Comparison
Compare different configurations:
# Scenario 1: Conventional (3 gensets)
system_conventional = create_conventional_system()
calc_conv = MachineryCalculation(system_conventional)
result_conv = calc_conv.calculate_machinery_system_output_from_propulsion_power_time_series(...)
# Scenario 2: Hybrid (2 gensets + battery)
system_hybrid = create_hybrid_system()
calc_hybrid = MachineryCalculation(system_hybrid)
result_hybrid = calc_hybrid.calculate_machinery_system_output_from_propulsion_power_time_series(...)
# Compare
fuel_savings = result_conv.multi_fuel_consumption_total_kg.fuels[0].mass_or_mass_fraction - \
result_hybrid.multi_fuel_consumption_total_kg.fuels[0].mass_or_mass_fraction
savings_pct = (fuel_savings / result_conv.multi_fuel_consumption_total_kg.fuels[0].mass_or_mass_fraction) * 100
print(f"Hybrid system saves {fuel_savings:.1f} kg ({savings_pct:.1f}%)")
4. PMS Optimization
Tune PMS parameters:
import matplotlib.pyplot as plt
# Test different thresholds
thresholds = [0.70, 0.75, 0.80, 0.85]
results = {}
for threshold in thresholds:
pms = PMSBasic(load_threshold_start=threshold)
calc = MachineryCalculation(system, pms=pms)
result = calc.calculate_machinery_system_output_from_propulsion_power_time_series(...)
results[threshold] = result
# Plot fuel consumption vs. threshold
fuel_consumptions = [r.multi_fuel_consumption_total_kg.fuels[0].mass_or_mass_fraction
for r in results.values()]
plt.plot(thresholds, fuel_consumptions)
plt.xlabel('Load Threshold')
plt.ylabel('Fuel Consumption (kg)')
plt.title('PMS Threshold Optimization')
plt.show()
Package Structure
RunFEEMSSim/
โโโ RunFeemsSim/
โ โโโ __init__.py
โ โโโ machinery_calculation.py # Core simulation interface
โ โโโ pms_basic.py # Power Management System
โ โโโ utils.py # Helper utilities
โโโ tests/
โ โโโ test_machinery_calculation.py
โ โโโ test_pms_basic.py
โโโ docs/ # Documentation
โโโ README.md
โโโ pyproject.toml
Requirements
- Python โฅ 3.10
- pandas
- numpy
- MachSysS
- feems
Related Packages
- feems: Core FEEMS library
- MachSysS: Data structures and protobuf definitions
Contributing
Contributions welcome! See CONTRIBUTING.md.
Development Setup
git clone https://github.com/SINTEF/FEEMS.git
cd FEEMS
uv sync
Making Changes
- Edit Python files directly in
RunFeemsSim/ - Add tests in
tests/ - Run tests:
uv run pytest RunFEEMSSim/tests/ - Lint code:
uv run ruff check RunFEEMSSim/ - Format code:
uv run ruff format RunFEEMSSim/ - Type check (optional):
uv run mypy RunFeemsSim/
Running Tests
# All tests
uv run pytest RunFEEMSSim/tests/
# Specific test file
uv run pytest RunFEEMSSim/tests/test_machinery_calculation.py
# With coverage
uv run pytest --cov=RunFeemsSim RunFEEMSSim/tests/
# Verbose output
uv run pytest -v RunFEEMSSim/tests/
Code Quality
# Check for issues
uv run ruff check RunFEEMSSim/
# Auto-fix issues
uv run ruff check --fix RunFEEMSSim/
# Format code
uv run ruff format RunFEEMSSim/
# Type checking
uv run mypy RunFeemsSim/
License
Licensed under the Apache License 2.0 - see LICENSE file for details.
Citation
@software{runfeemssim2024,
title = {RunFeemsSim: FEEMS Simulation Runner},
author = {Yum, Kevin Koosup and contributors},
year = {2024},
url = {https://github.com/SINTEF/FEEMS}
}
Support
- Issues: GitHub Issues
- Documentation: https://kevinkoosup.yum@sintef.no.github.io/RunFeemsSim/
- Email: kevinkoosup.yum@sintef.no
Acknowledgments
Developed by SINTEF Ocean as part of the FEEMS ecosystem for simplified marine power system simulation.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file runfeemssim-0.4.4.tar.gz.
File metadata
- Download URL: runfeemssim-0.4.4.tar.gz
- Upload date:
- Size: 20.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8d42d0c0e9f447449b86f922935852e82cf7b621cba4d80172242db6e5646140
|
|
| MD5 |
d0fe00e32a9c958f7d4755b1db03e45c
|
|
| BLAKE2b-256 |
396a7472fbd5e524f2a10e736523482e43c0bb61ea60997e3676890a4040e020
|
Provenance
The following attestation bundles were made for runfeemssim-0.4.4.tar.gz:
Publisher:
publish_RunFeemsSim.yml on SINTEF/FEEMS
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
runfeemssim-0.4.4.tar.gz -
Subject digest:
8d42d0c0e9f447449b86f922935852e82cf7b621cba4d80172242db6e5646140 - Sigstore transparency entry: 942076575
- Sigstore integration time:
-
Permalink:
SINTEF/FEEMS@58896fbcc3827214aadcc27d8d6395e3797da46f -
Branch / Tag:
refs/tags/RunFeemsSim-v0.4.4 - Owner: https://github.com/SINTEF
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish_RunFeemsSim.yml@58896fbcc3827214aadcc27d8d6395e3797da46f -
Trigger Event:
push
-
Statement type:
File details
Details for the file runfeemssim-0.4.4-py3-none-any.whl.
File metadata
- Download URL: runfeemssim-0.4.4-py3-none-any.whl
- Upload date:
- Size: 13.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
921f882c44922b384379525c69f6f064da079574663cb05587f84e3ac5f44d1b
|
|
| MD5 |
06e00af13d2f18b970ca599e327985d5
|
|
| BLAKE2b-256 |
d995ea0ed8b4e2cc48f59fd4944ed057a1a6b1b1a16c52aa5e4a987f3431f985
|
Provenance
The following attestation bundles were made for runfeemssim-0.4.4-py3-none-any.whl:
Publisher:
publish_RunFeemsSim.yml on SINTEF/FEEMS
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
runfeemssim-0.4.4-py3-none-any.whl -
Subject digest:
921f882c44922b384379525c69f6f064da079574663cb05587f84e3ac5f44d1b - Sigstore transparency entry: 942076580
- Sigstore integration time:
-
Permalink:
SINTEF/FEEMS@58896fbcc3827214aadcc27d8d6395e3797da46f -
Branch / Tag:
refs/tags/RunFeemsSim-v0.4.4 - Owner: https://github.com/SINTEF
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish_RunFeemsSim.yml@58896fbcc3827214aadcc27d8d6395e3797da46f -
Trigger Event:
push
-
Statement type: