Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: read requested pressures in compressor system #557

Merged
merged 12 commits into from
Aug 7, 2024
9 changes: 9 additions & 0 deletions src/libecalc/common/time_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ def get_timestep_indices(self, timesteps: List[datetime]) -> Tuple[int, int]:
f"Period: {self.start}:{self.end} - timesteps: {timesteps}"
) from e

def get_timesteps(self, timesteps: List[datetime]) -> List[datetime]:
TeeeJay marked this conversation as resolved.
Show resolved Hide resolved
"""
Get all given timesteps that are within this period.
Returns empty list if no timesteps are outside period.
"""
timesteps = [timestep for timestep in timesteps if self.__contains__(timestep)]

return timesteps


@dataclass
class Periods:
Expand Down
71 changes: 31 additions & 40 deletions src/libecalc/presentation/json_result/mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ def get_requested_compressor_pressures(
energy_usage_model: Dict[datetime, Any],
pressure_type: CompressorPressureType,
name: str,
model_period: Period,
model_timesteps: List[datetime],
operational_settings_used: Optional[TimeSeriesInt] = None,
) -> TemporalModel[Expression]:
Expand All @@ -79,49 +78,43 @@ def get_requested_compressor_pressures(
"""

evaluated_temporal_energy_usage_models = {}
default_date = datetime(1900, 1, 1, 0, 0)

# Extract relevant temporal model:
if len(energy_usage_model.items()) == 1 and default_date in energy_usage_model:
model_subset = TemporalModel(energy_usage_model).models[0].model
else:
model_subset = TemporalModel({model_period.start: energy_usage_model[model_period.start]}).models[0].model

if isinstance(model_subset, CompressorSystemConsumerFunction):
# Loop timesteps in temporal model, to find correct operational settings used:
for timestep in model_timesteps:
for compressor in model_subset.compressors:
if compressor.name == name:
operational_setting_used_id = get_operational_setting_used_id(
timestep=timestep, operational_settings_used=operational_settings_used
)

operational_setting = model_subset.operational_settings[operational_setting_used_id]
for period, model in TemporalModel(energy_usage_model).items():
if isinstance(model, CompressorSystemConsumerFunction):
# Loop timesteps in temporal model, to find correct operational settings used:
timesteps_in_period = period.get_timesteps(model_timesteps)
for timestep in timesteps_in_period:
for compressor in model.compressors:
if compressor.name == name:
operational_setting_used_id = get_operational_setting_used_id(
timestep=timestep, operational_settings_used=operational_settings_used
)

# Find correct compressor in case of different pressures for different components in system:
compressor_nr = int(
[i for i, compressor in enumerate(model_subset.compressors) if compressor.name == name][0]
)
operational_setting = model.operational_settings[operational_setting_used_id]

if pressure_type.value == CompressorPressureType.INLET_PRESSURE:
if operational_setting.suction_pressures is not None:
pressures = operational_setting.suction_pressures[compressor_nr]
else:
pressures = operational_setting.suction_pressure
else:
if operational_setting.discharge_pressures is not None:
pressures = operational_setting.discharge_pressures[compressor_nr]
# Find correct compressor in case of different pressures for different components in system:
compressor_nr = int(
[i for i, compressor in enumerate(model.compressors) if compressor.name == name][0]
)

if pressure_type.value == CompressorPressureType.INLET_PRESSURE:
if operational_setting.suction_pressures is not None:
pressures = operational_setting.suction_pressures[compressor_nr]
else:
pressures = operational_setting.suction_pressure
else:
pressures = operational_setting.discharge_pressure
if operational_setting.discharge_pressures is not None:
pressures = operational_setting.discharge_pressures[compressor_nr]
else:
pressures = operational_setting.discharge_pressure

if pressures is None:
pressures = math.nan
if pressures is None:
pressures = math.nan

if not isinstance(pressures, Expression):
pressures = Expression.setup_from_expression(value=pressures)
evaluated_temporal_energy_usage_models[timestep] = pressures
else:
for period, model in TemporalModel(energy_usage_model).items():
if not isinstance(pressures, Expression):
pressures = Expression.setup_from_expression(value=pressures)
evaluated_temporal_energy_usage_models[timestep] = pressures
else:
pressures = model.suction_pressure

if pressure_type.value == CompressorPressureType.OUTLET_PRESSURE:
Expand Down Expand Up @@ -446,7 +439,6 @@ def get_asset_result(graph_result: GraphResult) -> libecalc.presentation.json_re
operational_settings_used=consumer_result.component_result.operational_settings_used
if consumer_node_info.component_type == ComponentType.COMPRESSOR_SYSTEM
else None,
model_period=period,
model_timesteps=model.timesteps,
)
outlet_pressure_eval = get_requested_compressor_pressures(
Expand All @@ -456,7 +448,6 @@ def get_asset_result(graph_result: GraphResult) -> libecalc.presentation.json_re
operational_settings_used=consumer_result.component_result.operational_settings_used
if consumer_node_info.component_type == ComponentType.COMPRESSOR_SYSTEM
else None,
model_period=period,
model_timesteps=model.timesteps,
)

Expand Down
15 changes: 15 additions & 0 deletions src/tests/libecalc/common/test_time_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,21 @@ def test_end_not_defined(self):
assert datetime(2050, 1, 1) in period
assert datetime(4000, 1, 1) in period

def test_all_timesteps_in_period(self):
period = Period(start=datetime(2022, 1, 1), end=datetime(2030, 1, 1))
timesteps = [datetime(2022, 1, 1), datetime(2023, 1, 1)]
assert period.get_timesteps(timesteps) == timesteps

def test_some_timesteps_in_period(self):
period = Period(start=datetime(2022, 1, 1), end=datetime(2030, 1, 1))
timesteps = [datetime(2018, 1, 1), datetime(2022, 1, 1), datetime(2023, 1, 1)]
assert period.get_timesteps(timesteps) == [timesteps[1], timesteps[2]]

def test_no_timesteps_in_period(self):
period = Period(start=datetime(2022, 1, 1), end=datetime(2030, 1, 1))
timesteps = [datetime(2018, 1, 1), datetime(2019, 1, 1)]
assert period.get_timesteps(timesteps) == []


class TestCreatePeriods:
def test_single_date(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@
import pytest
from libecalc.application.energy_calculator import EnergyCalculator
from libecalc.application.graph_result import EcalcModelResult, GraphResult
from libecalc.common.component_info.compressor import CompressorPressureType
from libecalc.common.units import Unit
from libecalc.common.utils.rates import TimeSeriesFloat
from libecalc.presentation.json_result.mapper import get_asset_result
from libecalc.presentation.json_result.mapper import (
get_asset_result,
get_requested_compressor_pressures,
)
from libecalc.presentation.json_result.result.results import CompressorModelResult


Expand All @@ -22,6 +26,7 @@ def result(compressor_systems_and_compressor_train_temporal_dto) -> EcalcModelRe
variables_map=variables,
consumer_results=consumer_results,
)

result = get_asset_result(
GraphResult(
graph=graph,
Expand Down Expand Up @@ -116,3 +121,84 @@ def test_requested_pressures_compressor_system_temporal_model(result: EcalcModel
assert requested_inlet_pressure_train2_upgr == 45
assert requested_outlet_pressure_train1_upgr == 240
assert requested_outlet_pressure_train2_upgr == 245


def test_model_timestep_not_in_energy_usage_model(compressor_systems_and_compressor_train_temporal_dto):
graph = compressor_systems_and_compressor_train_temporal_dto.ecalc_model.get_graph()
compressor_system = graph.get_node("compressor_system_variable_speed_compressor_trains_multiple_pressures")

energy_usage_model = compressor_system.energy_usage_model

variables = compressor_systems_and_compressor_train_temporal_dto.variables
energy_calculator = EnergyCalculator(graph=graph)
consumer_results = energy_calculator.evaluate_energy_usage(variables)
operational_settings_used = consumer_results[
"compressor_system_variable_speed_compressor_trains_multiple_pressures"
].component_result.operational_settings_used

# Set some model time steps different from dates in temporal model
global_time_1 = datetime(2017, 1, 1)
global_time_2 = datetime(2018, 1, 5)
global_time_3 = datetime(2018, 6, 23, 17, 20, 50)
global_time_4 = datetime(2022, 1, 1)

model_timesteps = [
global_time_1,
global_time_2,
global_time_3,
global_time_4,
]

compressor_nr = 0

# Timesteps in operational settings must be equal to model timesteps.
# Basically replacing global timesteps, to have them different from
# the timesteps in the temporal model.
operational_settings_used.timesteps = model_timesteps

# Ensure that method do not fail if model timesteps do not correspond exactly to dates in temporal model
TeeeJay marked this conversation as resolved.
Show resolved Hide resolved
requested_inlet_pressures = get_requested_compressor_pressures(
energy_usage_model=energy_usage_model,
pressure_type=CompressorPressureType.INLET_PRESSURE,
model_timesteps=model_timesteps,
name="train1",
operational_settings_used=operational_settings_used,
)

# train1 is only active in first period defined in energy usage model, 1.1.2018 - 1.1.2019,
# hence only timesteps within this interval should be included:
assert requested_inlet_pressures.models[0].period.start == global_time_2
assert requested_inlet_pressures.models[1].period.start == global_time_3

# Get requested pressures for the two relevant timesteps
requested_inlet_pressure_2018_1_5 = requested_inlet_pressures.models[0].model.evaluate(
variables=variables.variables, fill_length=len(model_timesteps)
)
requested_inlet_pressure_2018_6_23 = requested_inlet_pressures.models[1].model.evaluate(
variables=variables.variables, fill_length=len(model_timesteps)
)

# Extract the correct operational setting (index) used for the given timesteps.
operational_setting_2018_1_5 = operational_settings_used.for_timestep(global_time_2).values[0] - 1
operational_setting_2018_6_23 = operational_settings_used.for_timestep(global_time_3).values[0] - 1

# Get input requested pressures from the relevant compressor and operational settings:
train1_inlet_pressures_operational_settings_2 = (
compressor_system.energy_usage_model[datetime(2018, 1, 1)]
.operational_settings[operational_setting_2018_1_5]
.suction_pressures[compressor_nr]
.evaluate(variables=variables.variables, fill_length=len(model_timesteps))
)

train1_inlet_pressures_operational_settings_1 = (
compressor_system.energy_usage_model[datetime(2018, 1, 1)]
.operational_settings[operational_setting_2018_6_23]
.suction_pressures[compressor_nr]
.evaluate(variables=variables.variables, fill_length=len(model_timesteps))
)

# Verify that extracted pressures for first timestep is correct, using the second operational setting
assert list(requested_inlet_pressure_2018_1_5) == list(train1_inlet_pressures_operational_settings_2)

# Verify that extracted pressures for second timestep is correct, using the first operational setting
assert list(requested_inlet_pressure_2018_6_23) == list(train1_inlet_pressures_operational_settings_1)