From 63010f3b5c3ec27cd2606e3ce2ef0d38a540cd1b Mon Sep 17 00:00:00 2001 From: Frode Helgetun Krogh <70878501+frodehk@users.noreply.github.com> Date: Mon, 23 Sep 2024 12:27:28 +0200 Subject: [PATCH] feat: add adjustment factor for models (new) (#611) * feat: add adjustment factor for models --- docs/docs/changelog/next.md | 1 + src/libecalc/core/models/compressor/base.py | 1 + .../core/models/compressor/train/base.py | 5 ++- ...on_shaft_multiple_streams_and_pressures.py | 5 ++- src/libecalc/core/models/turbine.py | 2 ++ .../presentation/yaml/mappers/model.py | 16 +++++----- .../presentation/yaml/yaml_keywords.py | 1 + .../models/yaml_compressor_trains.py | 20 ++++++++++++ .../models/yaml_compressor_with_turbine.py | 5 +++ .../yaml/yaml_types/models/yaml_turbine.py | 5 +++ ...ble_speed_compressor_train_common_shaft.py | 21 +++++++++++++ .../libecalc/core/models/test_turbine.py | 31 +++++++++++++++++-- 12 files changed, 101 insertions(+), 12 deletions(-) diff --git a/docs/docs/changelog/next.md b/docs/docs/changelog/next.md index a4533c941b..7b13ee57b1 100644 --- a/docs/docs/changelog/next.md +++ b/docs/docs/changelog/next.md @@ -21,6 +21,7 @@ sidebar_position: -1002 is any downstream choking, this will happen between the outlet of the last compressor stage and the outlet of the compressor train. This means that in a situation with downstream choking, the fluid stream leaving the compressor train will have lower e.g. pressure and density than the fluid stream leaving the last compressor stage. +- `POWER_ADJUSTMENT_FACTOR` for models: Optional factor to adjust the power (MW). Previously only the `POWER_ADJUSTMENT_CONSTANT` has been available for models, now it is possible to adjust/scale the power with a constant and a factor. It can be used to calibrate equipment. ## Fixes diff --git a/src/libecalc/core/models/compressor/base.py b/src/libecalc/core/models/compressor/base.py index fa6aa3de36..fb5fc3d459 100644 --- a/src/libecalc/core/models/compressor/base.py +++ b/src/libecalc/core/models/compressor/base.py @@ -130,6 +130,7 @@ def evaluate_turbine_based_on_compressor_model_result( load_adjusted = np.where( np.asarray(compressor_energy_function_result.power) > 0, np.asarray(compressor_energy_function_result.power) + * self.data_transfer_object.energy_usage_adjustment_factor + self.data_transfer_object.energy_usage_adjustment_constant, np.asarray(compressor_energy_function_result.power), ) diff --git a/src/libecalc/core/models/compressor/train/base.py b/src/libecalc/core/models/compressor/train/base.py index fd5b1a7ff2..fd1a60cfcd 100644 --- a/src/libecalc/core/models/compressor/train/base.py +++ b/src/libecalc/core/models/compressor/train/base.py @@ -136,7 +136,10 @@ def evaluate_rate_ps_pd( power_mw = np.array([result.power_megawatt for result in train_results]) power_mw_adjusted = np.where( - power_mw > 0, power_mw + self.data_transfer_object.energy_usage_adjustment_constant, power_mw + power_mw > 0, + power_mw * self.data_transfer_object.energy_usage_adjustment_factor + + self.data_transfer_object.energy_usage_adjustment_constant, + power_mw, ) max_standard_rate = np.full_like(rate, fill_value=INVALID_MAX_RATE, dtype=float) diff --git a/src/libecalc/core/models/compressor/train/variable_speed_compressor_train_common_shaft_multiple_streams_and_pressures.py b/src/libecalc/core/models/compressor/train/variable_speed_compressor_train_common_shaft_multiple_streams_and_pressures.py index 216a5b644c..ef95ea5806 100644 --- a/src/libecalc/core/models/compressor/train/variable_speed_compressor_train_common_shaft_multiple_streams_and_pressures.py +++ b/src/libecalc/core/models/compressor/train/variable_speed_compressor_train_common_shaft_multiple_streams_and_pressures.py @@ -892,7 +892,10 @@ def evaluate_rate_ps_pint_pd( power_mw = np.array([time_step.power_megawatt for time_step in train_results]) power_mw_adjusted = np.where( - power_mw > 0, power_mw + self.data_transfer_object.energy_usage_adjustment_constant, power_mw + power_mw > 0, + power_mw * self.data_transfer_object.energy_usage_adjustment_factor + + self.data_transfer_object.energy_usage_adjustment_constant, + power_mw, ) inlet_stream, outlet_stream, stage_results = CompressorTrainResultSingleTimeStep.from_result_list_to_dto( diff --git a/src/libecalc/core/models/turbine.py b/src/libecalc/core/models/turbine.py index e5da628492..58cd7ff545 100644 --- a/src/libecalc/core/models/turbine.py +++ b/src/libecalc/core/models/turbine.py @@ -40,6 +40,8 @@ def max_power(self) -> Optional[float]: ) def evaluate(self, load: NDArray[np.float64], fuel_lower_heating_value: float = 0) -> TurbineResult: + # Calibration of turbine load: + # Linear adjustment: (1/a)*x + b/a. load_adjusted = np.where( load > 0, (load + self.data_transfer_object.energy_usage_adjustment_constant) diff --git a/src/libecalc/presentation/yaml/mappers/model.py b/src/libecalc/presentation/yaml/mappers/model.py index 7e243a9f44..2ed4d26c78 100644 --- a/src/libecalc/presentation/yaml/mappers/model.py +++ b/src/libecalc/presentation/yaml/mappers/model.py @@ -367,7 +367,7 @@ def _variable_speed_compressor_train_multiple_streams_and_pressures_mapper( streams=streams, stages=stages, energy_usage_adjustment_constant=model_config.get(EcalcYamlKeywords.models_power_adjustment_constant_mw, 0), - energy_usage_adjustment_factor=1.0, + energy_usage_adjustment_factor=model_config.get(EcalcYamlKeywords.models_power_adjustment_factor_mw, 1), calculate_max_rate=model_config.get(EcalcYamlKeywords.calculate_max_rate, False), pressure_control=pressure_control, maximum_power=model_config.get(EcalcYamlKeywords.models_maximum_power, None), @@ -451,7 +451,7 @@ def _single_speed_compressor_train_mapper( pressure_control=pressure_control, maximum_discharge_pressure=maximum_discharge_pressure, energy_usage_adjustment_constant=model_config.get(EcalcYamlKeywords.models_power_adjustment_constant_mw, 0), - energy_usage_adjustment_factor=1.0, + energy_usage_adjustment_factor=model_config.get(EcalcYamlKeywords.models_power_adjustment_factor_mw, 1), calculate_max_rate=model_config.get(EcalcYamlKeywords.calculate_max_rate, False), maximum_power=model_config.get(EcalcYamlKeywords.models_maximum_power, None), ) @@ -521,7 +521,7 @@ def _variable_speed_compressor_train_mapper( fluid_model=fluid_model, stages=stages, energy_usage_adjustment_constant=model_config.get(EcalcYamlKeywords.models_power_adjustment_constant_mw, 0), - energy_usage_adjustment_factor=1.0, + energy_usage_adjustment_factor=model_config.get(EcalcYamlKeywords.models_power_adjustment_factor_mw, 1), calculate_max_rate=model_config.get(EcalcYamlKeywords.calculate_max_rate, False), pressure_control=pressure_control, maximum_power=model_config.get(EcalcYamlKeywords.models_maximum_power, None), @@ -583,7 +583,7 @@ def _simplified_variable_speed_compressor_train_mapper( for stage in stages ], energy_usage_adjustment_constant=model_config.get(EcalcYamlKeywords.models_power_adjustment_constant_mw, 0), - energy_usage_adjustment_factor=1.0, + energy_usage_adjustment_factor=model_config.get(EcalcYamlKeywords.models_power_adjustment_factor_mw, 1), calculate_max_rate=model_config.get(EcalcYamlKeywords.calculate_max_rate, False), maximum_power=model_config.get(EcalcYamlKeywords.models_maximum_power, None), ) @@ -602,7 +602,7 @@ def _simplified_variable_speed_compressor_train_mapper( remove_liquid_after_cooling=True, ), energy_usage_adjustment_constant=model_config.get(EcalcYamlKeywords.models_power_adjustment_constant_mw, 0), - energy_usage_adjustment_factor=1.0, + energy_usage_adjustment_factor=model_config.get(EcalcYamlKeywords.models_power_adjustment_factor_mw, 1), calculate_max_rate=model_config.get(EcalcYamlKeywords.calculate_max_rate, False), maximum_pressure_ratio_per_stage=train_spec.get( EcalcYamlKeywords.models_type_compressor_train_maximum_pressure_ratio_per_stage @@ -613,6 +613,7 @@ def _simplified_variable_speed_compressor_train_mapper( def _turbine_mapper(model_config: Dict, input_models: Dict[str, Any], resources: Resources) -> dto.Turbine: energy_usage_adjustment_constant = model_config.get(EcalcYamlKeywords.models_power_adjustment_constant_mw, 0) + energy_usage_adjustment_factor = model_config.get(EcalcYamlKeywords.models_power_adjustment_factor_mw, 1) return dto.Turbine( lower_heating_value=model_config.get(EcalcYamlKeywords.fuel_lower_heating_value), @@ -621,7 +622,7 @@ def _turbine_mapper(model_config: Dict, input_models: Dict[str, Any], resources: EcalcYamlKeywords.models_turbine_efficiency_table_efficiency_values ), energy_usage_adjustment_constant=energy_usage_adjustment_constant, - energy_usage_adjustment_factor=1.0, + energy_usage_adjustment_factor=energy_usage_adjustment_factor, ) @@ -645,12 +646,13 @@ def _compressor_with_turbine_mapper( if attr is None: raise ValueError(f"{attr_reference} not found in input models") energy_usage_adjustment_constant = model_config.get(EcalcYamlKeywords.models_power_adjustment_constant_mw, 0) + energy_usage_adjustment_factor = model_config.get(EcalcYamlKeywords.models_power_adjustment_factor_mw, 1) return dto.CompressorWithTurbine( compressor_train=compressor_train_model, turbine=turbine_model, energy_usage_adjustment_constant=energy_usage_adjustment_constant, - energy_usage_adjustment_factor=1.0, + energy_usage_adjustment_factor=energy_usage_adjustment_factor, ) diff --git a/src/libecalc/presentation/yaml/yaml_keywords.py b/src/libecalc/presentation/yaml/yaml_keywords.py index b2762f6110..5c8a11b2fd 100644 --- a/src/libecalc/presentation/yaml/yaml_keywords.py +++ b/src/libecalc/presentation/yaml/yaml_keywords.py @@ -176,6 +176,7 @@ class EcalcYamlKeywords: models_turbine_efficiency_table_efficiency_values = "TURBINE_EFFICIENCIES" models_type_compressor_with_turbine = "COMPRESSOR_WITH_TURBINE" models_power_adjustment_constant_mw = "POWER_ADJUSTMENT_CONSTANT" + models_power_adjustment_factor_mw = "POWER_ADJUSTMENT_FACTOR" models_maximum_power = "MAXIMUM_POWER" facility_adjustment = "ADJUSTMENT" diff --git a/src/libecalc/presentation/yaml/yaml_types/models/yaml_compressor_trains.py b/src/libecalc/presentation/yaml/yaml_types/models/yaml_compressor_trains.py index 9e41fae080..1be3b219da 100644 --- a/src/libecalc/presentation/yaml/yaml_types/models/yaml_compressor_trains.py +++ b/src/libecalc/presentation/yaml/yaml_types/models/yaml_compressor_trains.py @@ -65,6 +65,11 @@ class YamlSingleSpeedCompressorTrain(YamlCompressorTrainBase): description="Constant to adjust power usage in MW", title="POWER_ADJUSTMENT_CONSTANT", ) + power_adjustment_factor: float = Field( + 1.0, + description="Factor to adjust power usage in MW", + title="POWER_ADJUSTMENT_FACTOR", + ) fluid_model: FluidModelReference = Field(..., description="Reference to a fluid model", title="FLUID_MODEL") def to_dto(self): @@ -98,6 +103,11 @@ class YamlVariableSpeedCompressorTrain(YamlCompressorTrainBase): description="Constant to adjust power usage in MW", title="POWER_ADJUSTMENT_CONSTANT", ) + power_adjustment_factor: float = Field( + 1.0, + description="Factor to adjust power usage in MW", + title="POWER_ADJUSTMENT_FACTOR", + ) fluid_model: FluidModelReference = Field(..., description="Reference to a fluid model", title="FLUID_MODEL") def to_dto(self): @@ -127,6 +137,11 @@ class YamlSimplifiedVariableSpeedCompressorTrain(YamlCompressorTrainBase): description="Constant to adjust power usage in MW", title="POWER_ADJUSTMENT_CONSTANT", ) + power_adjustment_factor: float = Field( + 1.0, + description="Factor to adjust power usage in MW", + title="POWER_ADJUSTMENT_FACTOR", + ) def to_dto(self): raise NotImplementedError @@ -167,6 +182,11 @@ class YamlVariableSpeedCompressorTrainMultipleStreamsAndPressures(YamlCompressor description="Constant to adjust power usage in MW", title="POWER_ADJUSTMENT_CONSTANT", ) + power_adjustment_factor: float = Field( + 1.0, + description="Factor to adjust power usage in MW", + title="POWER_ADJUSTMENT_FACTOR", + ) def to_dto(self): raise NotImplementedError diff --git a/src/libecalc/presentation/yaml/yaml_types/models/yaml_compressor_with_turbine.py b/src/libecalc/presentation/yaml/yaml_types/models/yaml_compressor_with_turbine.py index 3ba0a7dda0..8df37a69a4 100644 --- a/src/libecalc/presentation/yaml/yaml_types/models/yaml_compressor_with_turbine.py +++ b/src/libecalc/presentation/yaml/yaml_types/models/yaml_compressor_with_turbine.py @@ -26,6 +26,11 @@ class YamlCompressorWithTurbine(YamlBase): description="Constant to adjust power usage in MW", title="POWER_ADJUSTMENT_CONSTANT", ) + power_adjustment_factor: float = Field( + 1.0, + description="Factor to adjust power usage in MW", + title="POWER_ADJUSTMENT_FACTOR", + ) turbine_model: TurbineModelReference = Field(..., description="Reference to a turbine model", title="TURBINE_MODEL") type: Literal[YamlModelType.COMPRESSOR_WITH_TURBINE] = Field( ..., diff --git a/src/libecalc/presentation/yaml/yaml_types/models/yaml_turbine.py b/src/libecalc/presentation/yaml/yaml_types/models/yaml_turbine.py index 1d7ee39f0a..52806e5f09 100644 --- a/src/libecalc/presentation/yaml/yaml_types/models/yaml_turbine.py +++ b/src/libecalc/presentation/yaml/yaml_types/models/yaml_turbine.py @@ -54,6 +54,11 @@ class YamlTurbine(YamlBase): description="Constant to adjust power usage in MW", title="POWER_ADJUSTMENT_CONSTANT", ) + power_adjustment_factor: float = Field( + 1.0, + description="Factor to adjust power usage in MW", + title="POWER_ADJUSTMENT_FACTOR", + ) def to_dto(self): raise NotImplementedError diff --git a/src/tests/libecalc/core/models/compressor_modelling/test_variable_speed_compressor_train_common_shaft.py b/src/tests/libecalc/core/models/compressor_modelling/test_variable_speed_compressor_train_common_shaft.py index e9002550dd..0831037674 100644 --- a/src/tests/libecalc/core/models/compressor_modelling/test_variable_speed_compressor_train_common_shaft.py +++ b/src/tests/libecalc/core/models/compressor_modelling/test_variable_speed_compressor_train_common_shaft.py @@ -363,3 +363,24 @@ def test_variable_speed_compressor_train_vs_unisim_methane(variable_speed_compre np.testing.assert_allclose(result.outlet_stream.temperature_kelvin, expected_outlet_temperature, rtol=0.05) np.testing.assert_allclose(result.outlet_stream.pressure, expected_outlet_pressure, rtol=0.06) np.testing.assert_allclose(result.stage_results[0].polytropic_efficiency, expected_efficiency, rtol=0.03) + + +def test_adjustment_constant_and_factor_one_compressor(variable_speed_compressor_train_one_compressor): + compressor_train = variable_speed_compressor_train_one_compressor + adjustment_constant = 10 + adjustment_factor = 1.5 + result = compressor_train.evaluate_rate_ps_pd( + rate=np.asarray([7000]), + suction_pressure=np.asarray([30]), + discharge_pressure=np.asarray([100.0]), + ) + + compressor_train.data_transfer_object.energy_usage_adjustment_factor = adjustment_factor + compressor_train.data_transfer_object.energy_usage_adjustment_constant = adjustment_constant + + result_adjusted = compressor_train.evaluate_rate_ps_pd( + rate=np.asarray([7000]), + suction_pressure=np.asarray([30]), + discharge_pressure=np.asarray([100.0]), + ) + assert result_adjusted.power[0] == result.power[0] * 1.5 + adjustment_constant diff --git a/src/tests/libecalc/core/models/test_turbine.py b/src/tests/libecalc/core/models/test_turbine.py index 1d25dabdcf..2ef37ada1c 100644 --- a/src/tests/libecalc/core/models/test_turbine.py +++ b/src/tests/libecalc/core/models/test_turbine.py @@ -38,10 +38,35 @@ def test_turbine_with_power_adjustment_constant(turbine: TurbineModel): def test_turbine_with_power_adjustment_factor(turbine: TurbineModel): - energy_usage_adjustment_factor = 0.9 - result_comparison = turbine.evaluate(load=np.asarray([2.352 / 2, 11.399])) + # Result without any adjustment: + result = turbine.evaluate(load=np.asarray([2.352 / 2, 11.399])) + # Set adjustment factor + energy_usage_adjustment_factor = 0.9 turbine.data_transfer_object.energy_usage_adjustment_factor = energy_usage_adjustment_factor + + # Result with adjustment: + result_adjusted = turbine.evaluate(load=np.asarray([2.352 / 2, 11.399])) + + # Compare: linear transformation is used to adjust (y = a*x + b. In this case b=0). + np.testing.assert_allclose(np.asarray(result.load) / energy_usage_adjustment_factor, result_adjusted.load) + + +def test_turbine_with_power_adjustment_constant_and_factor(turbine: TurbineModel): + # Result without any adjustment: result = turbine.evaluate(load=np.asarray([2.352 / 2, 11.399])) - np.testing.assert_allclose(np.asarray(result_comparison.load) / energy_usage_adjustment_factor, result.load) + # Set adjustment constant and factor + energy_usage_adjustment_constant = 1 + energy_usage_adjustment_factor = 2 + turbine.data_transfer_object.energy_usage_adjustment_factor = energy_usage_adjustment_factor + turbine.data_transfer_object.energy_usage_adjustment_constant = energy_usage_adjustment_constant + + # Result with adjustment: + result_adjusted = turbine.evaluate(load=np.asarray([2.352 / 2, 11.399])) + + # Compare: linear transformation is used to adjust (y = a*x + b). + np.testing.assert_allclose( + (np.asarray(result.load) + energy_usage_adjustment_constant) / energy_usage_adjustment_factor, + result_adjusted.load, + )