From 445fc9d856db729181e48f04d58cf05d324a8c50 Mon Sep 17 00:00:00 2001 From: Frode Helgetun Krogh <70878501+frodehk@users.noreply.github.com> Date: Fri, 6 Oct 2023 17:47:41 +0200 Subject: [PATCH] chore: handle requested pressures correct for compressors without system (#233) * chore: handle requested pressures correct for compressors without system --- src/libecalc/core/graph_result.py | 17 +- .../cases/all_energy_usage_models/__init__.py | 3 + .../all_energy_usage_models/all_models_dto.py | 177 ++++++++++++++++++ .../test_requested_pressures_compressors.py | 104 ++++++++++ 4 files changed, 293 insertions(+), 8 deletions(-) create mode 100644 src/tests/libecalc/dto/results/model/test_requested_pressures_compressors.py diff --git a/src/libecalc/core/graph_result.py b/src/libecalc/core/graph_result.py index 44b7572b75..f5020dcb6a 100644 --- a/src/libecalc/core/graph_result.py +++ b/src/libecalc/core/graph_result.py @@ -290,18 +290,19 @@ def get_requested_compressor_pressures( pressures = Expression.setup_from_expression(value=pressures) evaluated_temporal_energy_usage_models[timestep] = pressures else: - pressures = model_subset.suction_pressure + for period, model in TemporalModel(energy_usage_model).items(): + pressures = model.suction_pressure - if pressure_type.value == CompressorPressureType.OUTLET_PRESSURE: - pressures = model_subset.discharge_pressure + if pressure_type.value == CompressorPressureType.OUTLET_PRESSURE: + pressures = model.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) + if not isinstance(pressures, Expression): + pressures = Expression.setup_from_expression(value=pressures) - evaluated_temporal_energy_usage_models[model_period.start] = pressures + evaluated_temporal_energy_usage_models[period.start] = pressures return TemporalModel(evaluated_temporal_energy_usage_models) diff --git a/src/libecalc/fixtures/cases/all_energy_usage_models/__init__.py b/src/libecalc/fixtures/cases/all_energy_usage_models/__init__.py index 7f16a3b2d3..87d91d6ef2 100644 --- a/src/libecalc/fixtures/cases/all_energy_usage_models/__init__.py +++ b/src/libecalc/fixtures/cases/all_energy_usage_models/__init__.py @@ -9,6 +9,8 @@ compressor, compressor_system, compressor_system_variable_speed_compressor_trains, + compressor_system_variable_speed_compressor_trains_multiple_suction_discharge_pressures, + compressor_systems_and_compressor_train_temporal_dto, deh, flare, generic_from_design_point_compressor_train_consumer, @@ -21,6 +23,7 @@ simplified_compressor_system, simplified_compressor_train_predefined_variable_speed_charts_with_gerg_fluid, simplified_variable_speed_compressor_train_known_stages_consumer, + simplified_variable_speed_compressor_train_known_stages_consumer_temporal_model, simplified_variable_speed_compressor_train_unknown_stages_consumer, single_speed_compressor_train_asv_pressure_control, single_speed_compressor_train_downstream_choke_pressure_control, diff --git a/src/libecalc/fixtures/cases/all_energy_usage_models/all_models_dto.py b/src/libecalc/fixtures/cases/all_energy_usage_models/all_models_dto.py index 0764ed2dbb..7055364583 100644 --- a/src/libecalc/fixtures/cases/all_energy_usage_models/all_models_dto.py +++ b/src/libecalc/fixtures/cases/all_energy_usage_models/all_models_dto.py @@ -81,6 +81,107 @@ def compressor_system_variable_speed_compressor_trains( ) +@pytest.fixture +def compressor_system_variable_speed_compressor_trains_multiple_suction_discharge_pressures( + fuel_gas, + regularity, + compressor_train_variable_speed_user_defined_fluid_and_compressor_chart_and_turbine2, +) -> dto.FuelConsumer: + return dto.FuelConsumer( + name="compressor_system_variable_speed_compressor_trains_multiple_pressures", + component_type=ComponentType.COMPRESSOR_SYSTEM, + fuel=fuel_gas, + user_defined_category={datetime(1900, 1, 1): ConsumerUserDefinedCategoryType.COMPRESSOR}, + regularity=regularity, + energy_usage_model={ + datetime(2018, 1, 1): dto.CompressorSystemConsumerFunction( + energy_usage_type=dto.types.EnergyUsageType.FUEL, + power_loss_factor=Expression.setup_from_expression(value=0.05), + compressors=[ + dto.CompressorSystemCompressor( + name="train1", + compressor_train=compressor_train_variable_speed_user_defined_fluid_and_compressor_chart_and_turbine2, + ), + dto.CompressorSystemCompressor( + name="train2", + compressor_train=compressor_train_variable_speed_user_defined_fluid_and_compressor_chart_and_turbine2, + ), + dto.CompressorSystemCompressor( + name="train3", + compressor_train=compressor_train_variable_speed_user_defined_fluid_and_compressor_chart_and_turbine2, + ), + ], + operational_settings=[ + dto.CompressorSystemOperationalSetting( + rates=[ + Expression.setup_from_expression(value="SIM1;GAS_PROD {/} 2"), + Expression.setup_from_expression(value="SIM1;GAS_PROD {/} 2"), + Expression.setup_from_expression(value="SIM1;GAS_PROD {/} 2"), + ], + suction_pressures=[ + Expression.setup_from_expression(value=20), + Expression.setup_from_expression(value=30), + Expression.setup_from_expression(value=40), + ], + discharge_pressures=[ + Expression.setup_from_expression(value=220), + Expression.setup_from_expression(value=230), + Expression.setup_from_expression(value=240), + ], + ), + dto.CompressorSystemOperationalSetting( + rates=[ + Expression.setup_from_expression(value="SIM1;GAS_PROD {/} 3"), + Expression.setup_from_expression(value="SIM1;GAS_PROD {/} 3"), + Expression.setup_from_expression(value="SIM1;GAS_PROD {/} 3"), + ], + suction_pressures=[ + Expression.setup_from_expression(value=50), + Expression.setup_from_expression(value=60), + Expression.setup_from_expression(value=70), + ], + discharge_pressures=[ + Expression.setup_from_expression(value=250), + Expression.setup_from_expression(value=260), + Expression.setup_from_expression(value=270), + ], + ), + ], + ), + datetime(2019, 1, 1): dto.CompressorSystemConsumerFunction( + energy_usage_type=dto.types.EnergyUsageType.FUEL, + power_loss_factor=Expression.setup_from_expression(value=0.0), + compressors=[ + dto.CompressorSystemCompressor( + name="train1_upgraded", + compressor_train=compressor_train_variable_speed_user_defined_fluid_and_compressor_chart_and_turbine2, + ), + dto.CompressorSystemCompressor( + name="train2_upgraded", + compressor_train=compressor_train_variable_speed_user_defined_fluid_and_compressor_chart_and_turbine2, + ), + ], + operational_settings=[ + dto.CompressorSystemOperationalSetting( + rates=[ + Expression.setup_from_expression(value="SIM1;GAS_PROD {/} 2"), + Expression.setup_from_expression(value="SIM1;GAS_PROD {/} 2"), + ], + suction_pressures=[ + Expression.setup_from_expression(value=40), + Expression.setup_from_expression(value=45), + ], + discharge_pressures=[ + Expression.setup_from_expression(value=240), + Expression.setup_from_expression(value=245), + ], + ) + ], + ), + }, + ) + + @pytest.fixture def simplified_compressor_train_predefined_variable_speed_charts_with_gerg_fluid( simplified_variable_speed_compressor_train_with_gerg_fluid2, @@ -214,6 +315,35 @@ def simplified_variable_speed_compressor_train_known_stages_consumer( ) +@pytest.fixture +def simplified_variable_speed_compressor_train_known_stages_consumer_temporal_model( + simplified_variable_speed_compressor_train_known_stages, + regularity, +) -> dto.ElectricityConsumer: + return dto.ElectricityConsumer( + name="simplified_variable_speed_compressor_train_known_stages_consumer_temporal_model", + component_type=ComponentType.COMPRESSOR, + user_defined_category={datetime(1900, 1, 1): ConsumerUserDefinedCategoryType.COMPRESSOR}, + regularity=regularity, + energy_usage_model={ + datetime(2018, 1, 1): dto.CompressorConsumerFunction( + energy_usage_type=dto.types.EnergyUsageType.POWER, + rate_standard_m3_day=Expression.setup_from_expression(value=5000000), + suction_pressure=Expression.setup_from_expression(value=50), + discharge_pressure=Expression.setup_from_expression(value=250), + model=simplified_variable_speed_compressor_train_known_stages, + ), + datetime(2019, 1, 1): dto.CompressorConsumerFunction( + energy_usage_type=dto.types.EnergyUsageType.POWER, + rate_standard_m3_day=Expression.setup_from_expression(value=5000000), + suction_pressure=Expression.setup_from_expression(value=40), + discharge_pressure=Expression.setup_from_expression(value=260), + model=simplified_variable_speed_compressor_train_known_stages, + ), + }, + ) + + @pytest.fixture def generic_from_design_point_compressor_train_consumer( medium_fluid_dto, @@ -980,3 +1110,50 @@ def all_energy_usage_models_dto( ), all_energy_usage_models_variables, ) + + +@pytest.fixture +def compressor_systems_and_compressor_train_temporal_dto( + regularity, + fuel_gas, + genset_sampled, + simplified_variable_speed_compressor_train_known_stages_consumer_temporal_model, + compressor_system_variable_speed_compressor_trains_multiple_suction_discharge_pressures, + all_energy_usage_models_variables, +) -> DTOCase: + return DTOCase( + dto.Asset( + name="all_energy_usage_models", + installations=[ + dto.Installation( + user_defined_category=InstallationUserDefinedCategoryType.FIXED, + name="MAIN_INSTALLATION", + regularity=regularity, + hydrocarbon_export={ + datetime(1900, 1, 1): Expression.setup_from_expression( + value="SIM1;OIL_PROD {+} SIM1;GAS_PROD {/} 1000" + ), + }, + fuel_consumers=[ + dto.GeneratorSet( + name="GeneratorSet", + user_defined_category={ + datetime(1900, 1, 1): ConsumerUserDefinedCategoryType.TURBINE_GENERATOR + }, + generator_set_model={ + datetime(1900, 1, 1): genset_sampled, + datetime(2018, 1, 1): genset_sampled, + }, + regularity=regularity, + fuel=fuel_gas, + consumers=[ + simplified_variable_speed_compressor_train_known_stages_consumer_temporal_model, + ], + ), + compressor_system_variable_speed_compressor_trains_multiple_suction_discharge_pressures, + ], + ) + ], + ), + all_energy_usage_models_variables, + ) diff --git a/src/tests/libecalc/dto/results/model/test_requested_pressures_compressors.py b/src/tests/libecalc/dto/results/model/test_requested_pressures_compressors.py new file mode 100644 index 0000000000..88b4e0b5fc --- /dev/null +++ b/src/tests/libecalc/dto/results/model/test_requested_pressures_compressors.py @@ -0,0 +1,104 @@ +from datetime import datetime +from typing import List + +import pytest +from libecalc.core.ecalc import EnergyCalculator +from libecalc.core.graph_result import EcalcModelResult, GraphResult +from libecalc.dto.result.results import CompressorModelResult + + +@pytest.fixture +def result(compressor_systems_and_compressor_train_temporal_dto) -> EcalcModelResult: + ecalc_model = compressor_systems_and_compressor_train_temporal_dto.ecalc_model + variables = compressor_systems_and_compressor_train_temporal_dto.variables + + graph = ecalc_model.get_graph() + energy_calculator = EnergyCalculator(graph=graph) + consumer_results = energy_calculator.evaluate_energy_usage(variables) + emission_results = energy_calculator.evaluate_emissions( + variables_map=variables, + consumer_results=consumer_results, + ) + result = GraphResult( + graph=graph, + consumer_results=consumer_results, + variables_map=variables, + emission_results=emission_results, + ).get_asset_result() + + return result + + +def get_inlet_pressure(list_index: int, timestep: datetime, models: List[CompressorModelResult]) -> float: + return models[list_index].requested_inlet_pressure.for_timestep(timestep).values[0] + + +def get_outlet_pressure(list_index: int, timestep: datetime, models: List[CompressorModelResult]) -> float: + return models[list_index].requested_outlet_pressure.for_timestep(timestep).values[0] + + +def test_requested_pressures_compressor_train_temporal_model(result: EcalcModelResult): + """ + Check requested inlet- and outlet pressures for compressor trains, using temporal models. + + :param result: eCalc result including models with requested pressures + :return: Nothing + """ + date_temporal_1 = datetime(2018, 1, 1) + date_temporal_2 = datetime(2019, 1, 1) + models = result.models + + # Compressor train with temporal model + requested_inlet_pressure_date1 = get_inlet_pressure(0, date_temporal_1, models) + requested_inlet_pressure_date2 = get_inlet_pressure(0, date_temporal_2, models) + requested_outlet_pressure_date1 = get_outlet_pressure(0, date_temporal_1, models) + requested_outlet_pressure_date2 = get_outlet_pressure(0, date_temporal_2, models) + + # Temporal model 1 + assert requested_inlet_pressure_date1 == 50.0 + assert requested_outlet_pressure_date1 == 250.0 + + # Temporal model 2 + assert requested_inlet_pressure_date2 == 40.0 + assert requested_outlet_pressure_date2 == 260.0 + + +def test_requested_pressures_compressor_system_temporal_model(result: EcalcModelResult): + """ + Check requested inlet- and outlet pressures for compressor systems. + Use temporal models, different inlet/outlet pressures for each compressor in the system, + and several priorities (operational settings). + + :param result: eCalc result including models with requested pressures + :return: Nothing + """ + date_temporal_1 = datetime(2018, 1, 1) + date_temporal_2 = datetime(2019, 1, 1) + models = result.models + + # Compressor system with temporal model and inlet/outlet pressures per compressor + requested_inlet_pressure_train1 = get_inlet_pressure(1, date_temporal_1, models) + requested_inlet_pressure_train1_upgr = get_inlet_pressure(2, date_temporal_2, models) + requested_inlet_pressure_train2 = get_inlet_pressure(3, date_temporal_1, models) + requested_inlet_pressure_train2_upgr = get_inlet_pressure(4, date_temporal_2, models) + requested_inlet_pressure_train3 = get_inlet_pressure(5, date_temporal_1, models) + + requested_outlet_pressure_train1 = get_outlet_pressure(1, date_temporal_1, models) + requested_outlet_pressure_train1_upgr = get_outlet_pressure(2, date_temporal_2, models) + requested_outlet_pressure_train2 = get_outlet_pressure(3, date_temporal_1, models) + requested_outlet_pressure_train2_upgr = get_outlet_pressure(4, date_temporal_2, models) + requested_outlet_pressure_train3 = get_outlet_pressure(5, date_temporal_1, models) + + # Temporal model 1 + assert requested_inlet_pressure_train1 in [20.0, 50.0] + assert requested_inlet_pressure_train2 in [30.0, 60.0] + assert requested_inlet_pressure_train3 in [40.0, 70.0] + assert requested_outlet_pressure_train1 in [220.0, 250.0] + assert requested_outlet_pressure_train2 in [230.0, 260.0] + assert requested_outlet_pressure_train3 in [240.0, 270.0] + + # Temporal model 2 + assert requested_inlet_pressure_train1_upgr == 40 + assert requested_inlet_pressure_train2_upgr == 45 + assert requested_outlet_pressure_train1_upgr == 240 + assert requested_outlet_pressure_train2_upgr == 245