RunFeemsSim 0.2.4__tar.gz → 0.2.6__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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: RunFeemsSim
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Summary: A library for running feems simulation
5
5
  Home-page: https://github.com/SINTEF/FEEMS
6
6
  Author: Kevin Koosup Yum
@@ -21,6 +21,19 @@ Requires-Dist: pandas
21
21
  Requires-Dist: numpy
22
22
  Requires-Dist: MachSysS
23
23
  Provides-Extra: dev
24
+ Dynamic: author
25
+ Dynamic: author-email
26
+ Dynamic: classifier
27
+ Dynamic: description
28
+ Dynamic: description-content-type
29
+ Dynamic: home-page
30
+ Dynamic: keywords
31
+ Dynamic: license
32
+ Dynamic: license-file
33
+ Dynamic: provides-extra
34
+ Dynamic: requires-dist
35
+ Dynamic: requires-python
36
+ Dynamic: summary
24
37
 
25
38
  # RunFeemsSim Package
26
39
 
@@ -0,0 +1 @@
1
+ __version__ = "0.2.5"
@@ -8,15 +8,19 @@ __all__ = [
8
8
  ]
9
9
 
10
10
  # %% ../00_machinery_calculation.ipynb 3
11
- from typing import List, Union, Type, TypeVar
11
+ from typing import List, Optional, Union, Type, TypeVar
12
12
 
13
13
  import MachSysS.gymir_result_pb2 as proto_gymir
14
- from MachSysS.convert_proto_timeseries import convert_proto_timeseries_to_pd_dataframe
14
+ from MachSysS.convert_proto_timeseries import (
15
+ convert_proto_timeseries_to_pd_dataframe,
16
+ convert_proto_timeseries_for_multiple_propulsors_to_pd_dataframe,
17
+ )
15
18
  import numpy as np
16
19
  import pandas as pd
17
20
  from feems.components_model.utility import IntegrationMethod
18
21
  from feems.system_model import (
19
22
  ElectricPowerSystem,
23
+ FuelOption,
20
24
  HybridPropulsionSystem,
21
25
  MechanicalPropulsionSystemWithElectricPowerSystem,
22
26
  FEEMSResultForMachinerySystem,
@@ -95,43 +99,100 @@ class MachineryCalculation:
95
99
  def _set_input_load_time_interval_from_propulsion_power_time_series(
96
100
  self,
97
101
  *,
98
- propulsion_power_time_series: pd.Series,
102
+ propulsion_power_time_series: Union[pd.Series, pd.DataFrame],
99
103
  auxiliary_load_kw: Numeric,
100
104
  time_is_given_as_interval: bool = False,
101
105
  ) -> None:
102
- if time_is_given_as_interval:
103
- propulsion_power = propulsion_power_time_series.values
104
- time_interval_s = propulsion_power_time_series.index.to_numpy()
106
+ """Set the input load time interval from the propulsion power time series.
107
+ Args:
108
+ propulsion_power_time_series (Union[pd.Series, pd.DataFrame]): The propulsion power time series.
109
+ If it is a DataFrame, it should contain the propulsion power for each propulsion drive.
110
+ auxiliary_load_kw (Numeric): The auxiliary load in kW. It can be a single value or an array.
111
+ time_is_given_as_interval (bool): If True, the time series index is given as intervals.
112
+ Default is False, meaning the index is given as timestamps.
113
+ """
114
+ if not isinstance(propulsion_power_time_series, (pd.Series, pd.DataFrame)):
115
+ raise TypeError(
116
+ "propulsion_power_time_series must be a pandas Series or DataFrame."
117
+ )
118
+ if isinstance(propulsion_power_time_series, pd.Series):
119
+ if time_is_given_as_interval:
120
+ propulsion_power = propulsion_power_time_series.values
121
+ time_interval_s = propulsion_power_time_series.index.to_numpy()
122
+ else:
123
+ propulsion_power = propulsion_power_time_series.values[:-1]
124
+ time_interval_s = np.diff(propulsion_power_time_series.index.to_numpy())
125
+ number_points = len(propulsion_power)
126
+ # set power load
127
+ if self.system_is_not_electric:
128
+ number_of_propulsors = (
129
+ self.system_feems.mechanical_system.no_mechanical_loads
130
+ )
131
+ else:
132
+ number_of_propulsors = len(self.electric_system.propulsion_drives)
133
+ if self.system_is_not_electric:
134
+ for propulsor in self.system_feems.mechanical_system.mechanical_loads:
135
+ propulsor.set_power_input_from_output(
136
+ propulsion_power / number_of_propulsors
137
+ )
138
+ else:
139
+ for propulsor in self.electric_system.propulsion_drives:
140
+ propulsor.set_power_input_from_output(
141
+ propulsion_power / number_of_propulsors
142
+ )
105
143
  else:
106
- propulsion_power = propulsion_power_time_series.values[:-1]
107
- time_interval_s = np.diff(propulsion_power_time_series.index.to_numpy())
108
-
109
- number_points = len(propulsion_power)
144
+ if time_is_given_as_interval:
145
+ time_interval_s = propulsion_power_time_series.index.to_numpy()
146
+ else:
147
+ time_interval_s = np.diff(propulsion_power_time_series.index.to_numpy())
148
+ propulsion_power_time_series = propulsion_power_time_series.iloc[:-1]
149
+ number_points = len(propulsion_power_time_series)
150
+ for propulsor_name in propulsion_power_time_series.columns:
151
+ propulsor = None
152
+ if self.system_is_not_electric:
153
+ for (
154
+ each_shaft_line
155
+ ) in self.system_feems.mechanical_system.shaft_line:
156
+ try:
157
+ propulsor = (
158
+ each_shaft_line.get_component_by_name_power_type(
159
+ name=propulsor_name,
160
+ power_type=TypePower.POWER_CONSUMER,
161
+ )
162
+ )
163
+ except ValueError:
164
+ continue
165
+ else:
166
+ for (
167
+ swb_id,
168
+ each_switchboard,
169
+ ) in self.electric_system.switchboards.items():
170
+ try:
171
+ propulsor = (
172
+ each_switchboard._get_component_by_type_and_name(
173
+ name=propulsor_name,
174
+ power_type=TypePower.POWER_CONSUMER,
175
+ )
176
+ )
177
+ except ValueError:
178
+ continue
179
+ if propulsor is None:
180
+ raise ValueError(
181
+ f"Propulsor with name {propulsor_name} not found in the system."
182
+ )
183
+ propulsor.set_power_input_from_output(
184
+ propulsion_power_time_series[propulsor_name].values
185
+ )
110
186
  auxiliary_load_kw = np.atleast_1d(auxiliary_load_kw)
111
187
  if len(auxiliary_load_kw) > 1:
112
188
  auxiliary_load_kw = auxiliary_load_kw[:number_points]
113
189
  else:
114
190
  auxiliary_load_kw = np.repeat(auxiliary_load_kw, number_points)
115
- # set power load
116
- number_of_propulsors = len(self.electric_system.propulsion_drives)
117
- if self.system_is_not_electric:
118
- number_of_propulsors = (
119
- self.system_feems.mechanical_system.no_mechanical_loads
120
- )
121
191
  number_of_other_loads = len(self.electric_system.other_load)
122
192
  if number_of_other_loads == 0:
123
193
  assert np.all(
124
194
  np.atleast_1d(auxiliary_load_kw) == 0
125
195
  ), "Auxiliary load is not zero while other loads are not defined in the system."
126
- for propulsor in self.electric_system.propulsion_drives:
127
- propulsor.set_power_input_from_output(
128
- propulsion_power / number_of_propulsors
129
- )
130
- if self.system_is_not_electric:
131
- for propulsor in self.system_feems.mechanical_system.mechanical_loads:
132
- propulsor.set_power_input_from_output(
133
- propulsion_power / number_of_propulsors
134
- )
135
196
  for other_load in self.electric_system.other_load:
136
197
  other_load.power_input = auxiliary_load_kw / number_of_other_loads
137
198
  self.electric_system.set_time_interval(
@@ -167,12 +228,15 @@ class MachineryCalculation:
167
228
  self,
168
229
  fuel_specified_by: FuelSpecifiedBy = FuelSpecifiedBy.IMO,
169
230
  ignore_power_balance: bool = False,
231
+ fuel_option: Optional[FuelOption] = None,
170
232
  ) -> Union[FEEMSResult, FEEMSResultForMachinerySystem]:
171
233
  """Run the simulation and return the result.
172
234
 
173
235
  Args:
174
236
  fuel_specified_by(FuelSpecifiedBy): The fuel specified by IMO/EU/USER. Default is IMO.
175
237
  ignore_power_balance(bool): If True, the power balance calculation will be ignored.
238
+ fuel_option(FuelOption): The fuel option to be used in the simulation. If None, the
239
+ default fuel option in the system will be used.
176
240
 
177
241
  Returns:
178
242
  The result of the simulation. FEEMSResult or FEEMSResultForMachinery system.
@@ -183,10 +247,12 @@ class MachineryCalculation:
183
247
  time_interval_s=self.system_feems.mechanical_system.time_interval_s,
184
248
  integration_method=IntegrationMethod.sum_with_time,
185
249
  fuel_specified_by=fuel_specified_by,
250
+ fuel_option=fuel_option,
186
251
  )
187
252
  else:
188
253
  return self.system_feems.get_fuel_energy_consumption_running_time(
189
- fuel_specified_by=fuel_specified_by
254
+ fuel_specified_by=fuel_specified_by,
255
+ fuel_option=fuel_option,
190
256
  )
191
257
 
192
258
  power_kw_per_switchboard = (
@@ -205,11 +271,13 @@ class MachineryCalculation:
205
271
  time_interval_s=self.system_feems.mechanical_system.time_interval_s,
206
272
  integration_method=IntegrationMethod.sum_with_time,
207
273
  fuel_specified_by=fuel_specified_by,
274
+ fuel_option=fuel_option,
208
275
  )
209
276
  else:
210
277
  self.system_feems.do_power_balance_calculation()
211
278
  return self.system_feems.get_fuel_energy_consumption_running_time(
212
- fuel_specified_by=fuel_specified_by
279
+ fuel_specified_by=fuel_specified_by,
280
+ fuel_option=fuel_option,
213
281
  )
214
282
 
215
283
  def calculate_machinery_system_output_from_gymir_result(
@@ -218,6 +286,7 @@ class MachineryCalculation:
218
286
  gymir_result: proto_gymir.GymirResult,
219
287
  fuel_specified_by: FuelSpecifiedBy = FuelSpecifiedBy.IMO,
220
288
  ignore_power_balance: bool = False,
289
+ fuel_option: Optional[FuelOption] = None,
221
290
  ) -> Union[FEEMSResult, FEEMSResultForMachinerySystem]:
222
291
  """
223
292
  Calculate the machinery system output from a Gymir result.
@@ -226,6 +295,8 @@ class MachineryCalculation:
226
295
  gymir_result(GymirResult): Gymir result given as protobuf message.
227
296
  fuel_specified_by(FuelSpecifiedBy): The fuel specified by IMO/EU/USER. Default is IMO.
228
297
  ignore_power_balance(bool): If True, the power balance calculation will be ignored.
298
+ fuel_option(FuelOption): The fuel option to be used in the simulation. If None, the
299
+ default fuel option in the system will be used.
229
300
 
230
301
  Returns:
231
302
  The result of the calculation. FEEMSResult or FEEMSResultForMachinerySystem.
@@ -234,35 +305,66 @@ class MachineryCalculation:
234
305
  return self._run_simulation(
235
306
  fuel_specified_by=fuel_specified_by,
236
307
  ignore_power_balance=ignore_power_balance,
308
+ fuel_option=fuel_option,
237
309
  )
238
310
 
239
311
  def calculate_machinery_system_output_from_propulsion_power_time_series(
240
312
  self,
241
313
  *,
242
- propulsion_power: pd.Series,
314
+ propulsion_power: Union[pd.Series, pd.DataFrame],
243
315
  auxiliary_power_kw: Numeric,
244
316
  fuel_specified_by: FuelSpecifiedBy = FuelSpecifiedBy.IMO,
245
317
  ignore_power_balance: bool = False,
318
+ fuel_option: Optional[FuelOption] = None,
246
319
  ) -> Union[FEEMSResult, FEEMSResultForMachinerySystem]:
247
320
  """
248
321
  Calculate the machinery system output from a time series of the propulsion power and
249
322
  auxiliary power.
250
323
 
251
324
  Args:
252
- propulsion_power(pd.Series): The propulsion power time series.
325
+ propulsion_power: The propulsion power time series. It can be a pandas Series if the
326
+ data is the total propulsion power that is equally shared by all propulsion drives,
327
+ or a pandas DataFrame if the data is given for each propulsion drive separately.
253
328
  auxiliary_power_kw(Numeric): The auxiliary power in kW. It can be a single value or
254
329
  a numpy array with the same length as the propulsion power.
255
330
  fuel_specified_by(FuelSpecifiedBy): The fuel specified by IMO/EU/USER. Default is IMO.
256
331
  ignore_power_balance(bool): If True, the power balance calculation will be ignored.
332
+ fuel_option(FuelOption): The fuel option to be used in the simulation. If None, the
333
+ default fuel option in the system will be used.
257
334
 
258
335
  Returns:
259
336
  The result of the calculation. FEEMSResult or FEEMSResultForMachinerySystem.
260
337
  """
338
+ # Check if the propulsion power is a pandas Series or DataFrame
339
+ if not isinstance(propulsion_power, (pd.Series, pd.DataFrame)):
340
+ raise TypeError("propulsion_power must be a pandas Series or DataFrame.")
341
+ # If it's a DataFrame, ensure column names match the propulsion drives
342
+ if isinstance(propulsion_power, pd.DataFrame):
343
+ # Check for electric propulsion system
344
+ if self.system_is_not_electric:
345
+ names_for_propulsion_drives = [
346
+ drive.name
347
+ for drive in self.system_feems.mechanical_system.mechanical_loads
348
+ ]
349
+ for name in propulsion_power.columns:
350
+ assert (
351
+ name in names_for_propulsion_drives
352
+ ), f"Column '{name}' not found in mechanical loads."
353
+ else:
354
+ names_for_propulsion_drives = [
355
+ drive.name for drive in self.electric_system.propulsion_drives
356
+ ]
357
+ for name in propulsion_power.columns:
358
+ assert (
359
+ name in names_for_propulsion_drives
360
+ ), f"Column '{name}' not found in propulsion drives."
361
+ # Check if auxiliary_power_kw is a scalar or an array
261
362
  if not np.isscalar(auxiliary_power_kw):
262
363
  assert (
263
364
  len(propulsion_power) == len(auxiliary_power_kw)
264
365
  or len(auxiliary_power_kw) == 1
265
- ), "The length of the auxiliary power must be 1 or the same as the propulsion power"
366
+ ), f"The length of the auxiliary power({len(auxiliary_power_kw)}) must be 1 or the same as the propulsion power ({len(propulsion_power)})"
367
+
266
368
  self._set_input_load_time_interval_from_propulsion_power_time_series(
267
369
  propulsion_power_time_series=propulsion_power,
268
370
  auxiliary_load_kw=auxiliary_power_kw,
@@ -270,14 +372,19 @@ class MachineryCalculation:
270
372
  return self._run_simulation(
271
373
  fuel_specified_by=fuel_specified_by,
272
374
  ignore_power_balance=ignore_power_balance,
375
+ fuel_option=fuel_option,
273
376
  )
274
377
 
275
378
  def calculate_machinery_system_output_from_time_series_result(
276
379
  self,
277
380
  *,
278
- time_series: proto_gymir.TimeSeriesResult,
381
+ time_series: Union[
382
+ proto_gymir.TimeSeriesResult,
383
+ proto_gymir.TimeSeriesResultForMultiplePropulsors,
384
+ ],
279
385
  fuel_specified_by: FuelSpecifiedBy = FuelSpecifiedBy.IMO,
280
386
  ignore_power_balance: bool = False,
387
+ fuel_option: Optional[FuelOption] = None,
281
388
  ) -> Union[FEEMSResult, FEEMSResultForMachinerySystem]:
282
389
  """
283
390
  Calculate the machinery system output from statistics of the propulsion power.
@@ -285,18 +392,36 @@ class MachineryCalculation:
285
392
  time_series(TimeSeriesResult): Time series result given as protobuf message.
286
393
  fuel_specified_by(FuelSpecifiedBy): The fuel specified by IMO/EU/USER. Default is IMO.
287
394
  ignore_power_balance(bool): If True, the power balance calculation will be ignored.
395
+ fuel_option(FuelOption): The fuel option to be used in the simulation. If None, the
396
+ default fuel option in the system will be used.
288
397
 
289
398
  Returns:
290
399
  The result of the simulation. FEEMSResult or FEEMSResultForMachinery system.
291
400
  """
292
- df = convert_proto_timeseries_to_pd_dataframe(time_series)
293
- self._set_input_load_time_interval_from_propulsion_power_time_series(
294
- propulsion_power_time_series=df["propulsion_power_kw"],
295
- auxiliary_load_kw=df["auxiliary_power_kw"].values,
296
- )
401
+ if isinstance(time_series, proto_gymir.TimeSeriesResult):
402
+ df = convert_proto_timeseries_to_pd_dataframe(time_series)
403
+ self._set_input_load_time_interval_from_propulsion_power_time_series(
404
+ propulsion_power_time_series=df["propulsion_power_kw"],
405
+ auxiliary_load_kw=df["auxiliary_power_kw"].values,
406
+ )
407
+ elif isinstance(time_series, proto_gymir.TimeSeriesResultForMultiplePropulsors):
408
+ df = convert_proto_timeseries_for_multiple_propulsors_to_pd_dataframe(
409
+ time_series
410
+ )
411
+ propulsor_names = list(map(lambda each: each, time_series.propulsor_names))
412
+ self._set_input_load_time_interval_from_propulsion_power_time_series(
413
+ propulsion_power_time_series=df[propulsor_names],
414
+ auxiliary_load_kw=df["auxiliary_power_kw"].values,
415
+ )
416
+ else:
417
+ raise TypeError(
418
+ "time_series must be a TimeSeriesResult or TimeSeriesResultForMultiplePropulsors."
419
+ )
420
+
297
421
  return self._run_simulation(
298
422
  fuel_specified_by=fuel_specified_by,
299
423
  ignore_power_balance=ignore_power_balance,
424
+ fuel_option=fuel_option,
300
425
  )
301
426
 
302
427
  def calculate_machinery_system_output_from_statistics(
@@ -307,6 +432,7 @@ class MachineryCalculation:
307
432
  auxiliary_power_kw: Numeric,
308
433
  fuel_specified_by: FuelSpecifiedBy = FuelSpecifiedBy.IMO,
309
434
  ignore_power_balance: bool = False,
435
+ fuel_option: Optional[FuelOption] = None,
310
436
  ) -> Union[FEEMSResult, FEEMSResultForMachinerySystem]:
311
437
  """
312
438
  Calculate the machinery system output from statistics of the propulsion power.
@@ -319,6 +445,8 @@ class MachineryCalculation:
319
445
  possible to give a single value for all modes.
320
446
  fuel_specified_by(FuelSpecifiedBy): The fuel specified by IMO/EU/USER. Default is IMO.
321
447
  ignore_power_balance(bool): If True, the power balance calculation will be ignored.
448
+ fuel_option(FuelOption): The fuel option to be used in the simulation. If None, the
449
+ default fuel option in the system will be used.
322
450
 
323
451
  Returns:
324
452
  The result of the simulation. FEEMSResult or FEEMSResultForMachinery system.
@@ -338,4 +466,5 @@ class MachineryCalculation:
338
466
  return self._run_simulation(
339
467
  fuel_specified_by=fuel_specified_by,
340
468
  ignore_power_balance=ignore_power_balance,
469
+ fuel_option=fuel_option,
341
470
  )
@@ -198,8 +198,12 @@ class PmsLoadTableSimulationInterface(SimulationInterface):
198
198
  self._n_power_sources == number_power_sources
199
199
  ), f"The electric_power_system.power_sources count is different from {self._n_power_sources}"
200
200
  for i, source in enumerate(electric_power_system.power_sources):
201
- source.status = on_pattern_per_datapoint[:, i]
201
+ source.status = on_pattern_per_datapoint[:, i].astype(bool)
202
202
  source.load_sharing_mode = equal_load_sharing_vector
203
203
  for component in chain(electric_power_system.energy_storage):
204
- component.status = off_vector
204
+ component.status = off_vector.astype(bool)
205
205
  component.load_sharing_mode = equal_load_sharing_vector
206
+ for component in chain(electric_power_system.pti_pto):
207
+ component.status = off_vector.astype(bool)
208
+ component.load_sharing_mode = equal_load_sharing_vector
209
+ component.full_pti_mode = off_vector.astype(bool)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: RunFeemsSim
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Summary: A library for running feems simulation
5
5
  Home-page: https://github.com/SINTEF/FEEMS
6
6
  Author: Kevin Koosup Yum
@@ -21,6 +21,19 @@ Requires-Dist: pandas
21
21
  Requires-Dist: numpy
22
22
  Requires-Dist: MachSysS
23
23
  Provides-Extra: dev
24
+ Dynamic: author
25
+ Dynamic: author-email
26
+ Dynamic: classifier
27
+ Dynamic: description
28
+ Dynamic: description-content-type
29
+ Dynamic: home-page
30
+ Dynamic: keywords
31
+ Dynamic: license
32
+ Dynamic: license-file
33
+ Dynamic: provides-extra
34
+ Dynamic: requires-dist
35
+ Dynamic: requires-python
36
+ Dynamic: summary
24
37
 
25
38
  # RunFeemsSim Package
26
39
 
@@ -8,7 +8,7 @@ author = Kevin Koosup Yum
8
8
  author_email = kevinkoosup.yum@sintef.no
9
9
  copyright = SINTEF
10
10
  branch = master
11
- version = 0.2.4
11
+ version = 0.2.6
12
12
  min_python = 3.10
13
13
  audience = Developers
14
14
  language = English
@@ -1 +0,0 @@
1
- __version__ = "0.2.4"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes