RunFeemsSim 0.2.6__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- runfeemssim-0.5.0/PKG-INFO +562 -0
- runfeemssim-0.5.0/README.md +540 -0
- runfeemssim-0.5.0/RunFeemsSim/__init__.py +9 -0
- {runfeemssim-0.2.6 → runfeemssim-0.5.0}/RunFeemsSim/machinery_calculation.py +40 -62
- {runfeemssim-0.2.6 → runfeemssim-0.5.0}/RunFeemsSim/pms_basic.py +23 -51
- runfeemssim-0.5.0/RunFeemsSim.egg-info/PKG-INFO +562 -0
- {runfeemssim-0.2.6 → runfeemssim-0.5.0}/RunFeemsSim.egg-info/SOURCES.txt +4 -9
- {runfeemssim-0.2.6 → runfeemssim-0.5.0}/RunFeemsSim.egg-info/requires.txt +0 -4
- runfeemssim-0.5.0/pyproject.toml +31 -0
- runfeemssim-0.5.0/tests/test_machinery_calculation.py +463 -0
- runfeemssim-0.5.0/tests/test_pms_basic.py +18 -0
- runfeemssim-0.2.6/CONTRIBUTING.md +0 -33
- runfeemssim-0.2.6/MANIFEST.in +0 -5
- runfeemssim-0.2.6/PKG-INFO +0 -86
- runfeemssim-0.2.6/README.md +0 -49
- runfeemssim-0.2.6/RunFeemsSim/__init__.py +0 -1
- runfeemssim-0.2.6/RunFeemsSim/_modidx.py +0 -117
- runfeemssim-0.2.6/RunFeemsSim/_nbdev.py +0 -26
- runfeemssim-0.2.6/RunFeemsSim/py.typed +0 -0
- runfeemssim-0.2.6/RunFeemsSim.egg-info/PKG-INFO +0 -86
- runfeemssim-0.2.6/RunFeemsSim.egg-info/not-zip-safe +0 -1
- runfeemssim-0.2.6/settings.ini +0 -27
- runfeemssim-0.2.6/setup.py +0 -114
- {runfeemssim-0.2.6 → runfeemssim-0.5.0}/LICENSE +0 -0
- {runfeemssim-0.2.6 → runfeemssim-0.5.0}/RunFeemsSim.egg-info/dependency_links.txt +0 -0
- {runfeemssim-0.2.6 → runfeemssim-0.5.0}/RunFeemsSim.egg-info/top_level.txt +0 -0
- {runfeemssim-0.2.6 → runfeemssim-0.5.0}/setup.cfg +0 -0
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: RunFeemsSim
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: A library for running feems simulation
|
|
5
|
+
Author-email: Kevin Koosup Yum <kevinkoosup.yum@gmail.com>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Repository, https://github.com/SINTEF/FEEMS
|
|
8
|
+
Project-URL: Documentation, https://kevinkoosup.yum@sintef.no.github.io/RunFeemsSim/
|
|
9
|
+
Keywords: FEEMS,,machinery,system,,fuel,,emissions
|
|
10
|
+
Classifier: Natural Language :: English
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: pandas
|
|
19
|
+
Requires-Dist: numpy
|
|
20
|
+
Requires-Dist: MachSysS
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# RunFeemsSim - FEEMS Simulation Runner
|
|
24
|
+
|
|
25
|
+
[](https://badge.fury.io/py/RunFeemsSim)
|
|
26
|
+
[](https://www.python.org/downloads/)
|
|
27
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
|
28
|
+
|
|
29
|
+
**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.
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
### 🎯 High-Level Simulation Interface
|
|
34
|
+
- **Simple API**: Run complex simulations with minimal code
|
|
35
|
+
- **Time-Series Support**: Handle operational profiles over time
|
|
36
|
+
- **Automatic Power Balance**: Continuous load balancing across time points
|
|
37
|
+
- **Result Aggregation**: Comprehensive metrics collection
|
|
38
|
+
|
|
39
|
+
### 🔌 Power Management System (PMS)
|
|
40
|
+
- **Load-Dependent Control**: Automatic genset start/stop based on load
|
|
41
|
+
- **Multiple Strategies**: Configurable PMS algorithms
|
|
42
|
+
- **Efficiency Optimization**: Minimize fuel consumption
|
|
43
|
+
- **Blackout Prevention**: Ensure sufficient spinning reserve
|
|
44
|
+
|
|
45
|
+
### 📊 Results Analysis
|
|
46
|
+
- **Fuel Consumption**: Total and per-component fuel usage
|
|
47
|
+
- **Emissions**: CO2, NOx with FuelEU Maritime support
|
|
48
|
+
- **Energy Breakdown**: Propulsion vs. auxiliary energy
|
|
49
|
+
- **Operating Hours**: Runtime tracking for maintenance planning
|
|
50
|
+
|
|
51
|
+
### 🐍 Pure Python Development
|
|
52
|
+
- **Clean Python Modules**: Standard Python package structure
|
|
53
|
+
- **Easy to Understand**: Straightforward code organization
|
|
54
|
+
- **Simple to Extend**: Add new features easily
|
|
55
|
+
- **Type Hints**: Full type annotation support
|
|
56
|
+
|
|
57
|
+
## Installation
|
|
58
|
+
|
|
59
|
+
### From PyPI
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install RunFeemsSim
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
This will install RunFeemsSim along with its dependencies (feems, MachSysS).
|
|
66
|
+
|
|
67
|
+
### From Source (Developers)
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Clone repository
|
|
71
|
+
git clone https://github.com/SINTEF/FEEMS.git
|
|
72
|
+
cd FEEMS
|
|
73
|
+
|
|
74
|
+
# Install with uv (recommended)
|
|
75
|
+
uv sync
|
|
76
|
+
|
|
77
|
+
# Or with pip
|
|
78
|
+
pip install -e RunFEEMSSim/
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Quick Start
|
|
82
|
+
|
|
83
|
+
### Basic Simulation
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
import numpy as np
|
|
87
|
+
import pandas as pd
|
|
88
|
+
from RunFeemsSim.machinery_calculation import MachineryCalculation
|
|
89
|
+
from feems.system_model import ElectricPowerSystem
|
|
90
|
+
from feems.fuel import FuelSpecifiedBy
|
|
91
|
+
|
|
92
|
+
# Create or load a FEEMS system
|
|
93
|
+
system = ElectricPowerSystem(...)
|
|
94
|
+
|
|
95
|
+
# Initialize machinery calculation
|
|
96
|
+
machinery_calc = MachineryCalculation(system)
|
|
97
|
+
|
|
98
|
+
# Define propulsion power time series
|
|
99
|
+
n_points = 1000
|
|
100
|
+
time_step_s = 1.0
|
|
101
|
+
|
|
102
|
+
propulsion_power = pd.DataFrame({
|
|
103
|
+
'Propulsion Drive 1': 400 + 200 * np.random.random(n_points),
|
|
104
|
+
'Propulsion Drive 2': 300 + 150 * np.random.random(n_points)
|
|
105
|
+
}, index=np.arange(0, n_points * time_step_s, time_step_s))
|
|
106
|
+
|
|
107
|
+
# Define auxiliary power
|
|
108
|
+
auxiliary_power = 100 + 50 * np.random.random(n_points)
|
|
109
|
+
|
|
110
|
+
# Run simulation
|
|
111
|
+
result = machinery_calc.calculate_machinery_system_output_from_propulsion_power_time_series(
|
|
112
|
+
propulsion_power=propulsion_power,
|
|
113
|
+
auxiliary_power_kw=auxiliary_power,
|
|
114
|
+
fuel_specified_by=FuelSpecifiedBy.FUEL_EU_MARITIME
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Access results
|
|
118
|
+
print(f"Total fuel: {result.multi_fuel_consumption_total_kg.fuels[0].mass_or_mass_fraction:.2f} kg")
|
|
119
|
+
print(f"Total CO2: {result.co2_emission_total_kg.tank_to_wake_kg_or_gco2eq_per_gfuel:.2f} kg")
|
|
120
|
+
print(f"Genset hours: {result.running_hours_genset_total_hr:.2f} hr")
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### With Power Management System
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
from RunFeemsSim.pms_basic import PMSBasic
|
|
127
|
+
|
|
128
|
+
# Create PMS with load-dependent genset control
|
|
129
|
+
pms = PMSBasic(
|
|
130
|
+
load_threshold_start=0.75, # Start additional genset at 75% load
|
|
131
|
+
load_threshold_stop=0.40, # Stop genset when load drops below 40%
|
|
132
|
+
min_gensets_running=1 # Always keep at least 1 genset running
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Attach PMS to system
|
|
136
|
+
machinery_calc = MachineryCalculation(system, pms=pms)
|
|
137
|
+
|
|
138
|
+
# Run simulation with automatic genset management
|
|
139
|
+
result = machinery_calc.calculate_machinery_system_output_from_propulsion_power_time_series(
|
|
140
|
+
propulsion_power=propulsion_power,
|
|
141
|
+
auxiliary_power_kw=auxiliary_power,
|
|
142
|
+
fuel_specified_by=FuelSpecifiedBy.FUEL_EU_MARITIME
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# PMS automatically starts/stops gensets based on load
|
|
146
|
+
print(f"Genset start events: {pms.n_starts}")
|
|
147
|
+
print(f"Genset stop events: {pms.n_stops}")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Core Components
|
|
151
|
+
|
|
152
|
+
### MachineryCalculation
|
|
153
|
+
|
|
154
|
+
Main class for running simulations.
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
class MachineryCalculation:
|
|
158
|
+
"""High-level interface for FEEMS simulations."""
|
|
159
|
+
|
|
160
|
+
def __init__(self, system: ElectricPowerSystem, pms: Optional[PMS] = None):
|
|
161
|
+
"""
|
|
162
|
+
Initialize machinery calculation.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
system: FEEMS ElectricPowerSystem
|
|
166
|
+
pms: Optional Power Management System
|
|
167
|
+
"""
|
|
168
|
+
...
|
|
169
|
+
|
|
170
|
+
def calculate_machinery_system_output_from_propulsion_power_time_series(
|
|
171
|
+
self,
|
|
172
|
+
propulsion_power: pd.DataFrame,
|
|
173
|
+
auxiliary_power_kw: np.ndarray,
|
|
174
|
+
fuel_specified_by: FuelSpecifiedBy = FuelSpecifiedBy.IMO,
|
|
175
|
+
integration_method: IntegrationMethod = IntegrationMethod.simpson,
|
|
176
|
+
time_interval_s: float = 1.0
|
|
177
|
+
) -> ElectricSystemRunResult:
|
|
178
|
+
"""
|
|
179
|
+
Run simulation from propulsion power time series.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
propulsion_power: DataFrame with propulsion drive powers
|
|
183
|
+
Index: time in seconds
|
|
184
|
+
Columns: drive names
|
|
185
|
+
Values: power in kW
|
|
186
|
+
auxiliary_power_kw: Auxiliary load time series (kW)
|
|
187
|
+
fuel_specified_by: Emission calculation method
|
|
188
|
+
integration_method: Time integration method
|
|
189
|
+
time_interval_s: Time step in seconds
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
ElectricSystemRunResult with comprehensive metrics
|
|
193
|
+
"""
|
|
194
|
+
...
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### PMSBasic
|
|
198
|
+
|
|
199
|
+
Basic load-dependent Power Management System.
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
class PMSBasic:
|
|
203
|
+
"""
|
|
204
|
+
Basic PMS with load-dependent genset start/stop.
|
|
205
|
+
|
|
206
|
+
Starts additional gensets when load exceeds threshold.
|
|
207
|
+
Stops gensets when load drops below threshold.
|
|
208
|
+
Maintains minimum number of running gensets.
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
def __init__(
|
|
212
|
+
self,
|
|
213
|
+
load_threshold_start: float = 0.85,
|
|
214
|
+
load_threshold_stop: float = 0.40,
|
|
215
|
+
min_gensets_running: int = 1,
|
|
216
|
+
spinning_reserve: float = 0.20
|
|
217
|
+
):
|
|
218
|
+
"""
|
|
219
|
+
Initialize PMS.
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
load_threshold_start: Start genset when load > this (0-1)
|
|
223
|
+
load_threshold_stop: Stop genset when load < this (0-1)
|
|
224
|
+
min_gensets_running: Minimum gensets to keep running
|
|
225
|
+
spinning_reserve: Required spare capacity (0-1)
|
|
226
|
+
"""
|
|
227
|
+
...
|
|
228
|
+
|
|
229
|
+
def determine_genset_status(
|
|
230
|
+
self,
|
|
231
|
+
current_load_kw: float,
|
|
232
|
+
available_gensets: List[Genset],
|
|
233
|
+
current_status: np.ndarray
|
|
234
|
+
) -> np.ndarray:
|
|
235
|
+
"""
|
|
236
|
+
Determine which gensets should be running.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
current_load_kw: Total system load
|
|
240
|
+
available_gensets: List of all gensets
|
|
241
|
+
current_status: Current on/off status
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
Updated status array
|
|
245
|
+
"""
|
|
246
|
+
...
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Power Management Strategies
|
|
250
|
+
|
|
251
|
+
### Strategy 1: Load-Dependent Control
|
|
252
|
+
|
|
253
|
+
Automatically start/stop gensets based on load:
|
|
254
|
+
|
|
255
|
+
```python
|
|
256
|
+
pms = PMSBasic(
|
|
257
|
+
load_threshold_start=0.80, # Start at 80% of running capacity
|
|
258
|
+
load_threshold_stop=0.35, # Stop when below 35% of capacity
|
|
259
|
+
min_gensets_running=1 # Always keep 1 running
|
|
260
|
+
)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Behavior:**
|
|
264
|
+
- Load increases → Start additional gensets when threshold exceeded
|
|
265
|
+
- Load decreases → Stop gensets when load drops
|
|
266
|
+
- Prevents frequent switching with hysteresis
|
|
267
|
+
- Maintains spinning reserve
|
|
268
|
+
|
|
269
|
+
### Strategy 2: Time-Based Control
|
|
270
|
+
|
|
271
|
+
Control gensets based on time of day or operational mode:
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
# Define mode schedule
|
|
275
|
+
mode_schedule = pd.DataFrame({
|
|
276
|
+
'time': [0, 21600, 43200, 64800], # 0h, 6h, 12h, 18h
|
|
277
|
+
'mode': ['port', 'transit', 'transit', 'port']
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
# Different genset configurations per mode
|
|
281
|
+
genset_config = {
|
|
282
|
+
'port': [True, False, False], # 1 genset
|
|
283
|
+
'transit': [True, True, False], # 2 gensets
|
|
284
|
+
'maneuvering': [True, True, True] # 3 gensets
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Strategy 3: Efficiency Optimization
|
|
289
|
+
|
|
290
|
+
Run gensets at optimal load points:
|
|
291
|
+
|
|
292
|
+
```python
|
|
293
|
+
pms = PMSBasic(
|
|
294
|
+
load_threshold_start=0.75, # Target 75% load on running gensets
|
|
295
|
+
load_threshold_stop=0.40,
|
|
296
|
+
min_gensets_running=1
|
|
297
|
+
)
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
**Benefits:**
|
|
301
|
+
- Operates gensets in efficient range (70-85%)
|
|
302
|
+
- Minimizes fuel consumption
|
|
303
|
+
- Reduces emissions
|
|
304
|
+
|
|
305
|
+
## Development Workflow
|
|
306
|
+
|
|
307
|
+
RunFeemsSim follows standard Python development practices.
|
|
308
|
+
|
|
309
|
+
### Package Structure
|
|
310
|
+
|
|
311
|
+
```
|
|
312
|
+
RunFEEMSSim/
|
|
313
|
+
├── RunFeemsSim/
|
|
314
|
+
│ ├── __init__.py
|
|
315
|
+
│ ├── machinery_calculation.py # Core simulation logic
|
|
316
|
+
│ ├── pms_basic.py # Power Management System
|
|
317
|
+
│ └── utils.py # Utility functions
|
|
318
|
+
├── tests/
|
|
319
|
+
│ ├── test_machinery_calculation.py
|
|
320
|
+
│ └── test_pms_basic.py
|
|
321
|
+
├── README.md
|
|
322
|
+
└── pyproject.toml
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Development Cycle
|
|
326
|
+
|
|
327
|
+
1. **Edit Python Files**: Make changes directly in `.py` files
|
|
328
|
+
```bash
|
|
329
|
+
# Edit source files in your preferred editor/IDE
|
|
330
|
+
vim RunFeemsSim/machinery_calculation.py
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
2. **Run Tests**: Test your changes
|
|
334
|
+
```bash
|
|
335
|
+
uv run pytest RunFEEMSSim/tests/
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
3. **Lint and Format**: Ensure code quality
|
|
339
|
+
```bash
|
|
340
|
+
uv run ruff check RunFEEMSSim/
|
|
341
|
+
uv run ruff format RunFEEMSSim/
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
4. **Type Check**: Validate type hints (optional)
|
|
345
|
+
```bash
|
|
346
|
+
uv run mypy RunFeemsSim/
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
5. **Build**: Create distribution packages
|
|
350
|
+
```bash
|
|
351
|
+
cd RunFEEMSSim
|
|
352
|
+
uv build
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Why Pure Python?
|
|
356
|
+
|
|
357
|
+
- **Simplicity**: Standard Python package structure everyone knows
|
|
358
|
+
- **IDE Support**: Full autocomplete, refactoring, and debugging
|
|
359
|
+
- **Type Safety**: Use mypy and type hints effectively
|
|
360
|
+
- **Flexibility**: Easy integration with any Python tooling
|
|
361
|
+
- **Transparency**: Source code is exactly what gets executed
|
|
362
|
+
|
|
363
|
+
## Use Cases
|
|
364
|
+
|
|
365
|
+
### 1. Route Planning
|
|
366
|
+
|
|
367
|
+
Estimate fuel consumption for planned voyages:
|
|
368
|
+
|
|
369
|
+
```python
|
|
370
|
+
# Load route profile
|
|
371
|
+
route_profile = pd.read_csv('route_profile.csv') # time, speed, power
|
|
372
|
+
|
|
373
|
+
# Run simulation
|
|
374
|
+
machinery_calc = MachineryCalculation(system)
|
|
375
|
+
result = machinery_calc.calculate_machinery_system_output_from_propulsion_power_time_series(
|
|
376
|
+
propulsion_power=route_profile[['power']],
|
|
377
|
+
auxiliary_power_kw=route_profile['aux_power'].values
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
# Estimate fuel for voyage
|
|
381
|
+
fuel_kg = result.multi_fuel_consumption_total_kg.fuels[0].mass_or_mass_fraction
|
|
382
|
+
distance_nm = route_profile['distance'].sum()
|
|
383
|
+
fuel_per_nm = fuel_kg / distance_nm
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### 2. Emissions Reporting
|
|
387
|
+
|
|
388
|
+
Generate IMO/EU compliance reports:
|
|
389
|
+
|
|
390
|
+
```python
|
|
391
|
+
# Annual operation
|
|
392
|
+
annual_result = machinery_calc.calculate_machinery_system_output_from_propulsion_power_time_series(
|
|
393
|
+
propulsion_power=annual_profile,
|
|
394
|
+
auxiliary_power_kw=annual_aux,
|
|
395
|
+
fuel_specified_by=FuelSpecifiedBy.FUEL_EU_MARITIME
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
# FuelEU Maritime compliance
|
|
399
|
+
well_to_wake_co2 = annual_result.co2_emission_total_kg.well_to_wake_kg_or_gco2eq_per_gfuel
|
|
400
|
+
energy_consumed = annual_result.energy_consumption_propulsion_total_mj
|
|
401
|
+
ghg_intensity = well_to_wake_co2 / (energy_consumed / 1000) # gCO2eq/MJ
|
|
402
|
+
|
|
403
|
+
print(f"GHG Intensity: {ghg_intensity:.2f} gCO2eq/MJ")
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### 3. System Comparison
|
|
407
|
+
|
|
408
|
+
Compare different configurations:
|
|
409
|
+
|
|
410
|
+
```python
|
|
411
|
+
# Scenario 1: Conventional (3 gensets)
|
|
412
|
+
system_conventional = create_conventional_system()
|
|
413
|
+
calc_conv = MachineryCalculation(system_conventional)
|
|
414
|
+
result_conv = calc_conv.calculate_machinery_system_output_from_propulsion_power_time_series(...)
|
|
415
|
+
|
|
416
|
+
# Scenario 2: Hybrid (2 gensets + battery)
|
|
417
|
+
system_hybrid = create_hybrid_system()
|
|
418
|
+
calc_hybrid = MachineryCalculation(system_hybrid)
|
|
419
|
+
result_hybrid = calc_hybrid.calculate_machinery_system_output_from_propulsion_power_time_series(...)
|
|
420
|
+
|
|
421
|
+
# Compare
|
|
422
|
+
fuel_savings = result_conv.multi_fuel_consumption_total_kg.fuels[0].mass_or_mass_fraction - \
|
|
423
|
+
result_hybrid.multi_fuel_consumption_total_kg.fuels[0].mass_or_mass_fraction
|
|
424
|
+
savings_pct = (fuel_savings / result_conv.multi_fuel_consumption_total_kg.fuels[0].mass_or_mass_fraction) * 100
|
|
425
|
+
|
|
426
|
+
print(f"Hybrid system saves {fuel_savings:.1f} kg ({savings_pct:.1f}%)")
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### 4. PMS Optimization
|
|
430
|
+
|
|
431
|
+
Tune PMS parameters:
|
|
432
|
+
|
|
433
|
+
```python
|
|
434
|
+
import matplotlib.pyplot as plt
|
|
435
|
+
|
|
436
|
+
# Test different thresholds
|
|
437
|
+
thresholds = [0.70, 0.75, 0.80, 0.85]
|
|
438
|
+
results = {}
|
|
439
|
+
|
|
440
|
+
for threshold in thresholds:
|
|
441
|
+
pms = PMSBasic(load_threshold_start=threshold)
|
|
442
|
+
calc = MachineryCalculation(system, pms=pms)
|
|
443
|
+
result = calc.calculate_machinery_system_output_from_propulsion_power_time_series(...)
|
|
444
|
+
results[threshold] = result
|
|
445
|
+
|
|
446
|
+
# Plot fuel consumption vs. threshold
|
|
447
|
+
fuel_consumptions = [r.multi_fuel_consumption_total_kg.fuels[0].mass_or_mass_fraction
|
|
448
|
+
for r in results.values()]
|
|
449
|
+
plt.plot(thresholds, fuel_consumptions)
|
|
450
|
+
plt.xlabel('Load Threshold')
|
|
451
|
+
plt.ylabel('Fuel Consumption (kg)')
|
|
452
|
+
plt.title('PMS Threshold Optimization')
|
|
453
|
+
plt.show()
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
## Package Structure
|
|
457
|
+
|
|
458
|
+
```
|
|
459
|
+
RunFEEMSSim/
|
|
460
|
+
├── RunFeemsSim/
|
|
461
|
+
│ ├── __init__.py
|
|
462
|
+
│ ├── machinery_calculation.py # Core simulation interface
|
|
463
|
+
│ ├── pms_basic.py # Power Management System
|
|
464
|
+
│ └── utils.py # Helper utilities
|
|
465
|
+
├── tests/
|
|
466
|
+
│ ├── test_machinery_calculation.py
|
|
467
|
+
│ └── test_pms_basic.py
|
|
468
|
+
├── docs/ # Documentation
|
|
469
|
+
├── README.md
|
|
470
|
+
└── pyproject.toml
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
## Requirements
|
|
474
|
+
|
|
475
|
+
- Python ≥ 3.10
|
|
476
|
+
- pandas
|
|
477
|
+
- numpy
|
|
478
|
+
- MachSysS
|
|
479
|
+
- feems
|
|
480
|
+
|
|
481
|
+
## Related Packages
|
|
482
|
+
|
|
483
|
+
- **feems**: Core FEEMS library
|
|
484
|
+
- **MachSysS**: Data structures and protobuf definitions
|
|
485
|
+
|
|
486
|
+
## Contributing
|
|
487
|
+
|
|
488
|
+
Contributions welcome! See `CONTRIBUTING.md`.
|
|
489
|
+
|
|
490
|
+
### Development Setup
|
|
491
|
+
|
|
492
|
+
```bash
|
|
493
|
+
git clone https://github.com/SINTEF/FEEMS.git
|
|
494
|
+
cd FEEMS
|
|
495
|
+
uv sync
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Making Changes
|
|
499
|
+
|
|
500
|
+
1. **Edit Python files** directly in `RunFeemsSim/`
|
|
501
|
+
2. **Add tests** in `tests/`
|
|
502
|
+
3. **Run tests**: `uv run pytest RunFEEMSSim/tests/`
|
|
503
|
+
4. **Lint code**: `uv run ruff check RunFEEMSSim/`
|
|
504
|
+
5. **Format code**: `uv run ruff format RunFEEMSSim/`
|
|
505
|
+
6. **Type check** (optional): `uv run mypy RunFeemsSim/`
|
|
506
|
+
|
|
507
|
+
### Running Tests
|
|
508
|
+
|
|
509
|
+
```bash
|
|
510
|
+
# All tests
|
|
511
|
+
uv run pytest RunFEEMSSim/tests/
|
|
512
|
+
|
|
513
|
+
# Specific test file
|
|
514
|
+
uv run pytest RunFEEMSSim/tests/test_machinery_calculation.py
|
|
515
|
+
|
|
516
|
+
# With coverage
|
|
517
|
+
uv run pytest --cov=RunFeemsSim RunFEEMSSim/tests/
|
|
518
|
+
|
|
519
|
+
# Verbose output
|
|
520
|
+
uv run pytest -v RunFEEMSSim/tests/
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Code Quality
|
|
524
|
+
|
|
525
|
+
```bash
|
|
526
|
+
# Check for issues
|
|
527
|
+
uv run ruff check RunFEEMSSim/
|
|
528
|
+
|
|
529
|
+
# Auto-fix issues
|
|
530
|
+
uv run ruff check --fix RunFEEMSSim/
|
|
531
|
+
|
|
532
|
+
# Format code
|
|
533
|
+
uv run ruff format RunFEEMSSim/
|
|
534
|
+
|
|
535
|
+
# Type checking
|
|
536
|
+
uv run mypy RunFeemsSim/
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
## License
|
|
540
|
+
|
|
541
|
+
Licensed under the Apache License 2.0 - see LICENSE file for details.
|
|
542
|
+
|
|
543
|
+
## Citation
|
|
544
|
+
|
|
545
|
+
```bibtex
|
|
546
|
+
@software{runfeemssim2024,
|
|
547
|
+
title = {RunFeemsSim: FEEMS Simulation Runner},
|
|
548
|
+
author = {Yum, Kevin Koosup and contributors},
|
|
549
|
+
year = {2024},
|
|
550
|
+
url = {https://github.com/SINTEF/FEEMS}
|
|
551
|
+
}
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
## Support
|
|
555
|
+
|
|
556
|
+
- **Issues**: [GitHub Issues](https://github.com/SINTEF/FEEMS/issues)
|
|
557
|
+
- **Documentation**: [https://kevinkoosup.yum@sintef.no.github.io/RunFeemsSim/](https://kevinkoosup.yum@sintef.no.github.io/RunFeemsSim/)
|
|
558
|
+
- **Email**: kevinkoosup.yum@sintef.no
|
|
559
|
+
|
|
560
|
+
## Acknowledgments
|
|
561
|
+
|
|
562
|
+
Developed by SINTEF Ocean as part of the FEEMS ecosystem for simplified marine power system simulation.
|