diff --git a/src/ecalc_cli/commands/run.py b/src/ecalc_cli/commands/run.py index 01faadd41e..29f8f91ba3 100644 --- a/src/ecalc_cli/commands/run.py +++ b/src/ecalc_cli/commands/run.py @@ -134,11 +134,8 @@ def run( energy_calculator = EnergyCalculator(graph=model.get_graph()) precision = 6 - consumer_results = energy_calculator.evaluate_energy_usage(model.variables) - emission_results = energy_calculator.evaluate_emissions( - variables_map=model.variables, - consumer_results=consumer_results, - ) + consumer_results = energy_calculator.evaluate_energy_usage() + emission_results = energy_calculator.evaluate_emissions() results_core = GraphResult( graph=model.get_graph(), consumer_results=consumer_results, diff --git a/src/libecalc/application/energy/__init__.py b/src/libecalc/application/energy/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/libecalc/application/energy_calculator.py b/src/libecalc/application/energy_calculator.py index 1976ed170d..aab573f4f6 100644 --- a/src/libecalc/application/energy_calculator.py +++ b/src/libecalc/application/energy_calculator.py @@ -1,50 +1,18 @@ -from collections import defaultdict -from datetime import datetime -from functools import reduce from typing import Dict -import numpy as np - -import libecalc.dto.components -from libecalc.common.consumption_type import ConsumptionType -from libecalc.common.list.list_utils import elementwise_sum from libecalc.common.math.numbers import Numbers -from libecalc.common.priorities import PriorityID -from libecalc.common.priority_optimizer import PriorityOptimizer -from libecalc.common.temporal_model import TemporalModel -from libecalc.common.units import Unit -from libecalc.common.utils.rates import TimeSeriesInt, TimeSeriesString -from libecalc.common.variables import VariablesMap -from libecalc.core.consumers.consumer_system import ConsumerSystem -from libecalc.core.consumers.factory import create_consumer -from libecalc.core.consumers.generator_set import Genset -from libecalc.core.consumers.legacy_consumer.component import Consumer -from libecalc.core.consumers.legacy_consumer.consumer_function_mapper import EnergyModelMapper -from libecalc.core.models.fuel import FuelModel -from libecalc.core.models.generator import GeneratorModelSampled -from libecalc.core.result import ComponentResult, EcalcModelResult +from libecalc.common.utils.rates import TimeSeriesStreamDayRate +from libecalc.core.result import EcalcModelResult from libecalc.core.result.emission import EmissionResult -from libecalc.dto.component_graph import ComponentGraph -from libecalc.dto.components import ( - ConsumerSystem as ConsumerSystemDTO, -) -from libecalc.dto.components import ( - ElectricityConsumer as ElectricityConsumerDTO, -) -from libecalc.dto.components import ( - FuelConsumer as FuelConsumerDTO, -) -from libecalc.dto.components import ( - GeneratorSet as GeneratorSetDTO, +from libecalc.dto.component_graph import ( + Component, + ComponentGraph, + Emitter, + FuelConsumer, + PowerConsumer, + PowerProvider, + ProcessGraph, ) -from libecalc.presentation.yaml.yaml_types.emitters.yaml_venting_emitter import ( - YamlDirectTypeEmitter, - YamlOilTypeEmitter, -) - - -def merge_results(results_per_timestep: Dict[datetime, EcalcModelResult]) -> EcalcModelResult: - return reduce(lambda acc, x: acc.merge(x), results_per_timestep.values()) class EnergyCalculator: @@ -54,181 +22,55 @@ def __init__( ): self._graph = graph - def evaluate_energy_usage(self, variables_map: VariablesMap) -> Dict[str, EcalcModelResult]: + def evaluate_energy_usage(self) -> Dict[str, EcalcModelResult]: component_ids = list(reversed(self._graph.sorted_node_ids)) - component_dtos = [self._graph.get_node(component_id) for component_id in component_ids] + components_to_evaluate = [self._graph.get_node(component_id) for component_id in component_ids] consumer_results: Dict[str, EcalcModelResult] = {} + power_requirements: Dict[str, TimeSeriesStreamDayRate] = {} - for component_dto in component_dtos: - if isinstance(component_dto, (ElectricityConsumerDTO, FuelConsumerDTO)): - consumer = Consumer( - id=component_dto.id, - name=component_dto.name, - component_type=component_dto.component_type, - regularity=TemporalModel(component_dto.regularity), - consumes=component_dto.consumes, - energy_usage_model=TemporalModel( - { - start_time: EnergyModelMapper.from_dto_to_domain(model) - for start_time, model in component_dto.energy_usage_model.items() - } - ), - ) - consumer_results[component_dto.id] = consumer.evaluate(expression_evaluator=variables_map) - elif isinstance(component_dto, GeneratorSetDTO): - fuel_consumer = Genset( - id=component_dto.id, - name=component_dto.name, - temporal_generator_set_model=TemporalModel( - { - start_time: GeneratorModelSampled( - fuel_values=model.fuel_values, - power_values=model.power_values, - energy_usage_adjustment_constant=model.energy_usage_adjustment_constant, - energy_usage_adjustment_factor=model.energy_usage_adjustment_factor, - ) - for start_time, model in component_dto.generator_set_model.items() - } - ), - ) + for component in components_to_evaluate: + if isinstance(component, PowerConsumer): + power_requirements[component.id] = component.get_power_requirement() - power_requirement = elementwise_sum( - *[ - consumer_results[consumer_id].component_result.power.values - for consumer_id in self._graph.get_successors(component_dto.id) - ], - timesteps=variables_map.time_vector, - ) + elif isinstance(component, PowerProvider): + power_consumers_for_provider = self._graph.get_successors(component.id) + power_requirements_for_provider = [ + power_requirements[power_consumer_id] for power_consumer_id in power_consumers_for_provider + ] + component.provide_power(power_requirements_for_provider) - consumer_results[component_dto.id] = EcalcModelResult( - component_result=fuel_consumer.evaluate( - expression_evaluator=variables_map, - power_requirement=power_requirement, - ), - models=[], - sub_components=[], - ) - elif isinstance(component_dto, libecalc.dto.components.ConsumerSystem): - evaluated_stream_conditions = component_dto.evaluate_stream_conditions( - expression_evaluator=variables_map, - ) - optimizer = PriorityOptimizer() + elif isinstance(component, FuelConsumer): + component.get_fuel_usage() - results_per_timestep: Dict[str, Dict[datetime, ComponentResult]] = defaultdict(dict) - priorities_used = TimeSeriesString( - timesteps=[], - values=[], - unit=Unit.NONE, - ) - for timestep in variables_map.time_vector: - consumers_for_timestep = [ - create_consumer( - consumer=consumer, - timestep=timestep, - ) - for consumer in component_dto.consumers - ] + elif isinstance(component, ProcessGraph): + component.evaluate() - consumer_system = ConsumerSystem( - id=component_dto.id, - consumers=consumers_for_timestep, - component_conditions=component_dto.component_conditions, - ) - - def evaluator(priority: PriorityID): - stream_conditions_for_priority = evaluated_stream_conditions[priority] - stream_conditions_for_timestep = { - component_id: [ - stream_condition.for_timestep(timestep) for stream_condition in stream_conditions - ] - for component_id, stream_conditions in stream_conditions_for_priority.items() - } - return consumer_system.evaluate_consumers(stream_conditions_for_timestep) - - optimizer_result = optimizer.optimize( - priorities=list(evaluated_stream_conditions.keys()), - evaluator=evaluator, - ) - priorities_used.append(timestep=timestep, value=optimizer_result.priority_used) - for consumer_result in optimizer_result.priority_results: - results_per_timestep[consumer_result.id][timestep] = consumer_result - - # merge consumer results - consumer_ids = [consumer.id for consumer in component_dto.consumers] - merged_consumer_results = [] - for consumer_id in consumer_ids: - first_result, *rest_results = list(results_per_timestep[consumer_id].values()) - merged_consumer_results.append(first_result.merge(*rest_results)) - - # Convert to legacy compatible operational_settings_used - priorities_to_int_map = { - priority_name: index + 1 for index, priority_name in enumerate(evaluated_stream_conditions.keys()) - } - operational_settings_used = TimeSeriesInt( - timesteps=priorities_used.timesteps, - values=[priorities_to_int_map[priority_name] for priority_name in priorities_used.values], - unit=priorities_used.unit, - ) - - system_result = ConsumerSystem.get_system_result( - id=component_dto.id, - consumer_results=merged_consumer_results, - operational_settings_used=operational_settings_used, - ) - consumer_results[component_dto.id] = system_result - for consumer_result in merged_consumer_results: - consumer_results[consumer_result.id] = EcalcModelResult( - component_result=consumer_result, - sub_components=[], - models=[], - ) + for component in components_to_evaluate: + if isinstance(component, ProcessGraph): + for sub_component in component.get_components(): + consumer_results[sub_component.id] = sub_component.get_ecalc_model_result() + elif isinstance(component, Component): + consumer_results[component.id] = component.get_ecalc_model_result() return Numbers.format_results_to_precision(consumer_results, precision=6) def evaluate_emissions( - self, variables_map: VariablesMap, consumer_results: Dict[str, EcalcModelResult] + self, ) -> Dict[str, Dict[str, EmissionResult]]: """ Calculate emissions for fuel consumers and emitters - Args: - variables_map: - consumer_results: - Returns: a mapping from consumer_id to emissions """ emission_results: Dict[str, Dict[str, EmissionResult]] = {} for consumer_dto in self._graph.nodes.values(): - if isinstance(consumer_dto, (FuelConsumerDTO, GeneratorSetDTO)): - fuel_model = FuelModel(consumer_dto.fuel) - energy_usage = consumer_results[consumer_dto.id].component_result.energy_usage - emission_results[consumer_dto.id] = fuel_model.evaluate_emissions( - expression_evaluator=variables_map, - fuel_rate=np.asarray(energy_usage.values), - ) - elif isinstance(consumer_dto, ConsumerSystemDTO): - if consumer_dto.consumes == ConsumptionType.FUEL: - fuel_model = FuelModel(consumer_dto.fuel) - energy_usage = consumer_results[consumer_dto.id].component_result.energy_usage - emission_results[consumer_dto.id] = fuel_model.evaluate_emissions( - expression_evaluator=variables_map, fuel_rate=np.asarray(energy_usage.values) - ) - elif isinstance(consumer_dto, (YamlDirectTypeEmitter, YamlOilTypeEmitter)): - installation_id = self._graph.get_parent_installation_id(consumer_dto.id) - installation = self._graph.get_node(installation_id) + if isinstance(consumer_dto, Emitter): + emission_results[consumer_dto.id] = consumer_dto.get_emissions() - venting_emitter_results = {} - emission_rates = consumer_dto.get_emissions( - expression_evaluator=variables_map, regularity=installation.regularity - ) + elif isinstance(consumer_dto, ProcessGraph): + for sub_component in consumer_dto.get_components(): + if isinstance(sub_component, Emitter): + emission_results[sub_component.id] = sub_component.get_emissions() - for emission_name, emission_rate in emission_rates.items(): - emission_result = EmissionResult( - name=emission_name, - timesteps=variables_map.time_vector, - rate=emission_rate, - ) - venting_emitter_results[emission_name] = emission_result - emission_results[consumer_dto.id] = venting_emitter_results return Numbers.format_results_to_precision(emission_results, precision=6) diff --git a/src/libecalc/application/graph_result.py b/src/libecalc/application/graph_result.py index 816903cefb..8d7265bad5 100644 --- a/src/libecalc/application/graph_result.py +++ b/src/libecalc/application/graph_result.py @@ -28,7 +28,7 @@ def __init__( self.variables_map = variables_map def get_subgraph(self, node_id: str) -> "GraphResult": - subgraph = self.graph.get_node(node_id).get_graph() + subgraph = self.graph.get_subgraph(node_id) return GraphResult( graph=subgraph, diff --git a/src/libecalc/common/errors/exceptions.py b/src/libecalc/common/errors/exceptions.py index 08b13cc3cd..db1234ea75 100644 --- a/src/libecalc/common/errors/exceptions.py +++ b/src/libecalc/common/errors/exceptions.py @@ -64,13 +64,6 @@ def __init__(self, message: str): super().__init__("Illegal state", message, error_type=EcalcErrorType.SERVER_ERROR) -class InvalidReferenceException(EcalcError): - """The data provided is missing a required reference.""" - - def __init__(self, message: str): - super().__init__("Invalid reference", message, error_type=EcalcErrorType.CLIENT_ERROR) - - class InvalidDateException(EcalcError): ... diff --git a/src/libecalc/common/graph.py b/src/libecalc/common/graph.py index e1ff1ff792..8d5d58f392 100644 --- a/src/libecalc/common/graph.py +++ b/src/libecalc/common/graph.py @@ -1,5 +1,6 @@ from __future__ import annotations +import abc from typing import Dict, Generic, List, Protocol, TypeVar import networkx as nx @@ -10,6 +11,7 @@ class NodeWithID(Protocol): @property + @abc.abstractmethod def id(self) -> NodeID: ... @@ -17,9 +19,9 @@ def id(self) -> NodeID: ... class Graph(Generic[TNode]): - def __init__(self): - self.graph = nx.DiGraph() - self.nodes: Dict[NodeID, TNode] = {} + def __init__(self, graph: nx.DiGraph = None, nodes: Dict[NodeID, TNode] = None): + self.graph = nx.DiGraph() if graph is None else graph + self.nodes: Dict[NodeID, TNode] = {} if nodes is None else nodes def add_node(self, node: TNode) -> Self: self.graph.add_node(node.id) @@ -38,6 +40,19 @@ def add_subgraph(self, subgraph: Graph) -> Self: self.graph = nx.compose(self.graph, subgraph.graph) return self + def get_subgraph(self, node_id: NodeID) -> Self: + node_ids = {node_id, *self.get_successors(node_id, recursively=True)} + sub_graph = self.__class__() + for node in self.nodes.values(): + if node.id in node_ids: + sub_graph.add_node(node) + + for from_id, to_id in self.graph.edges: + if from_id in node_ids and to_id in node_ids: + sub_graph.add_edge(from_id, to_id) + + return sub_graph + def get_successors(self, node_id: NodeID, recursively=False) -> List[NodeID]: if recursively: return [ diff --git a/src/libecalc/common/time_utils.py b/src/libecalc/common/time_utils.py index 06e9effa38..412708d2d4 100644 --- a/src/libecalc/common/time_utils.py +++ b/src/libecalc/common/time_utils.py @@ -41,6 +41,9 @@ def __contains__(self, time: datetime) -> bool: """ return self.start <= time < self.end + def __eq__(self, other): + return self.start == other.start and self.end == other.end + @staticmethod def intersects(first: Period, second: Period) -> bool: """ diff --git a/src/libecalc/common/variables.py b/src/libecalc/common/variables.py index 3a0d3963d5..012b226d2a 100644 --- a/src/libecalc/common/variables.py +++ b/src/libecalc/common/variables.py @@ -82,7 +82,7 @@ def evaluate(self, expression: Union[Expression, Dict[datetime, Expression], Tem if isinstance(expression, Expression): return expression.evaluate(variables=self.variables, fill_length=len(self.get_time_vector())) elif isinstance(expression, dict): - return self._evaluate_temporal(temporal_expression=TemporalModel[expression]) + return self._evaluate_temporal(temporal_expression=TemporalModel(expression)) elif isinstance(expression, TemporalModel): return self._evaluate_temporal(temporal_expression=expression) diff --git a/src/libecalc/core/consumers/base/component.py b/src/libecalc/core/consumers/base/component.py index a5191d90be..53ba46b99f 100644 --- a/src/libecalc/core/consumers/base/component.py +++ b/src/libecalc/core/consumers/base/component.py @@ -1,10 +1,10 @@ from abc import ABC, abstractmethod from typing import List -from libecalc.common.stream_conditions import TimeSeriesStreamConditions from libecalc.common.utils.rates import TimeSeriesFloat from libecalc.common.variables import ExpressionEvaluator from libecalc.core.result import EcalcModelResult +from libecalc.domain.stream_conditions import StreamConditions class BaseConsumer(ABC): @@ -20,9 +20,7 @@ class BaseConsumerWithoutOperationalSettings(ABC): id: str @abstractmethod - def get_max_rate( - self, inlet_stream: TimeSeriesStreamConditions, target_pressure: TimeSeriesFloat - ) -> List[float]: ... + def get_max_rate(self, inlet_stream: StreamConditions, target_pressure: TimeSeriesFloat) -> List[float]: ... @abstractmethod - def evaluate(self, **kwargs) -> EcalcModelResult: ... + def evaluate(self, streams: List[StreamConditions]) -> EcalcModelResult: ... diff --git a/src/libecalc/core/consumers/consumer_system.py b/src/libecalc/core/consumers/consumer_system.py index 6b9b4f7ed6..4e793f03a3 100644 --- a/src/libecalc/core/consumers/consumer_system.py +++ b/src/libecalc/core/consumers/consumer_system.py @@ -1,7 +1,7 @@ import itertools import operator from functools import reduce -from typing import Dict, List, Optional, Protocol, Tuple, TypeVar, Union +from typing import Dict, Generic, List, Optional, Protocol, Tuple, TypeVar import networkx as nx @@ -9,12 +9,11 @@ from libecalc.common.utils.rates import ( TimeSeriesInt, ) -from libecalc.core.consumers.compressor import Compressor -from libecalc.core.consumers.pump import Pump +from libecalc.core.consumers.base import BaseConsumerWithoutOperationalSettings from libecalc.core.result import ComponentResult, ConsumerSystemResult, EcalcModelResult from libecalc.domain.stream_conditions import Rate, StreamConditions -Consumer = TypeVar("Consumer", bound=Union[Compressor, Pump]) +Consumer = TypeVar("Consumer", bound=BaseConsumerWithoutOperationalSettings) class Crossover(Protocol): @@ -27,7 +26,7 @@ class SystemComponentConditions(Protocol): crossover: List[Crossover] -class ConsumerSystem: +class ConsumerSystem(Generic[Consumer]): """ A system of possibly interdependent consumers and or other consumer systems. @@ -37,9 +36,7 @@ class ConsumerSystem: for a period of time -> Turn of compressor #2, and vice versa. """ - def __init__( - self, id: str, consumers: List[Union[Compressor, Pump]], component_conditions: SystemComponentConditions - ): + def __init__(self, id: str, consumers: List[Consumer], component_conditions: SystemComponentConditions): self.id = id self._consumers = consumers self._component_conditions = component_conditions @@ -76,8 +73,8 @@ def _get_stream_conditions_adjusted_for_crossover( if has_crossover_out: # TODO: Mix inlet streams and check pressure? Is consumer a Compressor or Pump or should it actually be trains also? Currently it is trains also. max_rate = consumer.get_max_rate( - inlet_stream=inlet_streams[0], - target_pressure=consumer_stream_conditions[-1].pressure, + inlet_stream=inlet_streams[0], # First inlet stream + target_pressure=consumer_stream_conditions[-1].pressure, # Outlet stream pressure ) crossover_stream, inlet_streams = ConsumerSystem._get_crossover_stream( max_rate, diff --git a/src/libecalc/dto/component_graph.py b/src/libecalc/dto/component_graph.py index 383187b47a..117854d73c 100644 --- a/src/libecalc/dto/component_graph.py +++ b/src/libecalc/dto/component_graph.py @@ -1,15 +1,98 @@ from __future__ import annotations -from typing import List +import abc +from typing import Dict, List, Optional, Union from libecalc.common.component_info.component_level import ComponentLevel from libecalc.common.component_type import ComponentType -from libecalc.common.graph import Graph, NodeID +from libecalc.common.graph import Graph +from libecalc.common.time_utils import Period +from libecalc.common.utils.rates import TimeSeriesStreamDayRate +from libecalc.core.result import EcalcModelResult +from libecalc.core.result.emission import EmissionResult from libecalc.dto.node_info import NodeInfo +ComponentID = str -class ComponentGraph(Graph): - def get_parent_installation_id(self, node_id: NodeID) -> NodeID: + +class Component(abc.ABC): + """ + Common info for a component in the model + """ + + @property + @abc.abstractmethod + def id(self) -> ComponentID: ... + + @property + @abc.abstractmethod + def name(self) -> str: ... + + @abc.abstractmethod + def get_node_info(self) -> NodeInfo: ... + + @abc.abstractmethod + def get_ecalc_model_result(self) -> Optional[EcalcModelResult]: + """ + TODO: We should look into removing this generic result, as it does not makes sense to provide the same result for all types of components. + """ + ... + + +class PowerProvider(Component, abc.ABC): + """ + Provider that can deliver a power requirement + """ + + @abc.abstractmethod + def provide_power(self, power_requirement: List[TimeSeriesStreamDayRate]): ... + + +class Emitter(Component, abc.ABC): + """ + Something that causes emissions + """ + + @abc.abstractmethod + def get_emissions(self, period: Period = None) -> Dict[str, EmissionResult]: ... + + +class PowerConsumer(Component, abc.ABC): + """ + A consumer with a power requirement + """ + + @abc.abstractmethod + def get_power_requirement(self, period: Period = None) -> TimeSeriesStreamDayRate: ... + + +class FuelConsumer(Emitter, abc.ABC): + """ + An abstraction for provider and consumer that isn't able to give power requirement + """ + + @abc.abstractmethod + def get_fuel_usage(self, period: Period = None) -> TimeSeriesStreamDayRate: ... + + +class ProcessGraph: + """ + A set of components that should be evaluated together, but reported as separate components. + """ + + @abc.abstractmethod + def get_components(self) -> List[Component]: ... + + @abc.abstractmethod + def evaluate(self) -> None: ... + + +# TODO: Refactor ComponentGraph to EnergyGraph, protocol and composition instead of inherit from graph. +# EnergyGraph should know about ProcessGraph. + + +class ComponentGraph(Graph[Union[Emitter, PowerConsumer, FuelConsumer, PowerProvider]]): + def get_parent_installation_id(self, node_id: ComponentID) -> ComponentID: """ Simple helper function to get the installation of any component with id @@ -28,36 +111,16 @@ def get_parent_installation_id(self, node_id: NodeID) -> NodeID: parent_id = self.get_predecessor(node_id) return self.get_parent_installation_id(parent_id) - def get_node_info(self, node_id: NodeID) -> NodeInfo: - component_dto = self.nodes[node_id] - if component_dto.component_type == ComponentType.ASSET: - component_level = ComponentLevel.ASSET - elif component_dto.component_type == ComponentType.INSTALLATION: - component_level = ComponentLevel.INSTALLATION - elif component_dto.component_type == ComponentType.GENERATOR_SET: - component_level = ComponentLevel.GENERATOR_SET - elif component_dto.component_type in [ - ComponentType.COMPRESSOR_SYSTEM, - ComponentType.PUMP_SYSTEM, - ComponentType.CONSUMER_SYSTEM_V2, - ]: - component_level = ComponentLevel.SYSTEM - else: - component_level = ComponentLevel.CONSUMER - - return NodeInfo( - id=component_dto.id, - name=component_dto.name, - component_type=component_dto.component_type, - component_level=component_level, - ) - - def get_node_id_by_name(self, name: str) -> NodeID: + def get_node_info(self, node_id: ComponentID) -> NodeInfo: + node = self.nodes[node_id] + return node.get_node_info() + + def get_node_id_by_name(self, name: str) -> ComponentID: for node in self.nodes.values(): if node.name == name: return node.id raise ValueError(f"Component with name '{name}' not found in '{self.nodes[self.root].name}'") - def get_nodes_of_type(self, component_type: ComponentType) -> List[NodeID]: - return [node.id for node in self.nodes.values() if node.component_type == component_type] + def get_nodes_of_type(self, component_type: ComponentType) -> List[ComponentID]: + return [node.id for node in self.nodes.values() if node.get_node_info().component_type == component_type] diff --git a/src/libecalc/dto/components.py b/src/libecalc/dto/components.py index 82e4067a3b..f5484530f7 100644 --- a/src/libecalc/dto/components.py +++ b/src/libecalc/dto/components.py @@ -7,6 +7,7 @@ from pydantic_core.core_schema import ValidationInfo from typing_extensions import Annotated +from libecalc.common.component_info.component_level import ComponentLevel from libecalc.common.component_type import ComponentType from libecalc.common.consumption_type import ConsumptionType from libecalc.common.energy_usage_type import EnergyUsageType @@ -33,6 +34,7 @@ ) from libecalc.dto.models.compressor import CompressorModel from libecalc.dto.models.pump import PumpModel +from libecalc.dto.node_info import NodeInfo from libecalc.dto.types import ConsumerUserDefinedCategoryType, InstallationUserDefinedCategoryType from libecalc.dto.utils.validators import ( ComponentNameStr, @@ -44,7 +46,6 @@ from libecalc.presentation.yaml.ltp_validation import ( validate_generator_set_power_from_shore, ) -from libecalc.presentation.yaml.yaml_keywords import EcalcYamlKeywords from libecalc.presentation.yaml.yaml_types.emitters.yaml_venting_emitter import ( YamlVentingEmitter, ) @@ -135,6 +136,14 @@ class ElectricityConsumer(BaseConsumer): lambda data: check_model_energy_usage_type(data, EnergyUsageType.POWER) ) + def get_node_info(self) -> NodeInfo: + return NodeInfo( + id=self.id, + name=self.name, + component_level=ComponentLevel.CONSUMER, + component_type=self.component_type, + ) + class FuelConsumer(BaseConsumer): component_type: Literal[ @@ -152,6 +161,14 @@ class FuelConsumer(BaseConsumer): lambda data: check_model_energy_usage_type(data, EnergyUsageType.FUEL) ) + def get_node_info(self) -> NodeInfo: + return NodeInfo( + id=self.id, + name=self.name, + component_level=ComponentLevel.CONSUMER, + component_type=self.component_type, + ) + Consumer = Annotated[Union[FuelConsumer, ElectricityConsumer], Field(discriminator="consumes")] @@ -243,6 +260,14 @@ class ConsumerSystem(BaseConsumer): stream_conditions_priorities: Priorities[SystemStreamConditions] consumers: Union[List[CompressorComponent], List[PumpComponent]] + def get_node_info(self) -> NodeInfo: + return NodeInfo( + id=self.id, + name=self.name, + component_level=ComponentLevel.SYSTEM, + component_type=self.component_type, + ) + def get_graph(self) -> ComponentGraph: graph = ComponentGraph() graph.add_node(self) @@ -355,6 +380,14 @@ def get_graph(self) -> ComponentGraph: return graph + def get_node_info(self) -> NodeInfo: + return NodeInfo( + id=self.id, + name=self.name, + component_level=ComponentLevel.GENERATOR_SET, + component_type=self.component_type, + ) + class Installation(BaseComponent): component_type: Literal[ComponentType.INSTALLATION] = ComponentType.INSTALLATION @@ -378,32 +411,6 @@ def id(self) -> str: convert_expression ) - @field_validator("user_defined_category", mode="before") - def check_user_defined_category(cls, user_defined_category, info: ValidationInfo): - """Provide which value and context to make it easier for user to correct wrt mandatory changes.""" - if user_defined_category is not None: - if user_defined_category not in list(InstallationUserDefinedCategoryType): - name_context_str = "" - if (name := info.data.get("name")) is not None: - name_context_str = f"with the name {name}" - - raise ValueError( - f"CATEGORY: {user_defined_category} is not allowed for {cls.__name__} {name_context_str}. Valid categories are: {[str(installation_user_defined_category.value) for installation_user_defined_category in InstallationUserDefinedCategoryType]}" - ) - - return user_defined_category - - @model_validator(mode="after") - def check_fuel_consumers_or_venting_emitters_exist(self): - try: - if self.fuel_consumers or self.venting_emitters or self.generator_sets: - return self - except AttributeError: - raise ValueError( - f"Keywords are missing:\n It is required to specify at least one of the keywords " - f"{EcalcYamlKeywords.fuel_consumers}, {EcalcYamlKeywords.generator_sets} or {EcalcYamlKeywords.installation_venting_emitters} in the model.", - ) from None - def get_graph(self) -> ComponentGraph: graph = ComponentGraph() graph.add_node(self) @@ -417,6 +424,14 @@ def get_graph(self) -> ComponentGraph: return graph + def get_node_info(self) -> NodeInfo: + return NodeInfo( + id=self.id, + name=self.name, + component_level=ComponentLevel.INSTALLATION, + component_type=self.component_type, + ) + class Asset(Component): @property @@ -483,6 +498,14 @@ def get_graph(self) -> ComponentGraph: return graph + def get_node_info(self) -> NodeInfo: + return NodeInfo( + id=self.id, + name=self.name, + component_level=ComponentLevel.ASSET, + component_type=self.component_type, + ) + ComponentDTO = Union[ Asset, diff --git a/src/libecalc/fixtures/cases/ltp_export/loading_storage_ltp_yaml.py b/src/libecalc/fixtures/cases/ltp_export/loading_storage_ltp_yaml.py index f074e58ca4..f819749383 100644 --- a/src/libecalc/fixtures/cases/ltp_export/loading_storage_ltp_yaml.py +++ b/src/libecalc/fixtures/cases/ltp_export/loading_storage_ltp_yaml.py @@ -1,11 +1,13 @@ +from io import StringIO +from pathlib import Path from typing import List -import yaml - +from ecalc_cli.infrastructure.file_resource_service import FileResourceService +from ecalc_cli.types import Frequency from libecalc.common.utils.rates import RateType -from libecalc.dto import Asset -from libecalc.presentation.yaml.parse_input import map_yaml_to_dto -from libecalc.presentation.yaml.yaml_models.pyyaml_yaml_model import PyYamlYamlModel +from libecalc.fixtures.cases.ltp_export.ltp_power_from_shore_yaml import OverridableStreamConfigurationService +from libecalc.presentation.yaml.model import YamlModel +from libecalc.presentation.yaml.yaml_entities import ResourceStream def ltp_oil_loaded_yaml_factory( @@ -16,7 +18,7 @@ def ltp_oil_loaded_yaml_factory( regularity: float, categories: List[str], consumer_names: List[str], -) -> Asset: +) -> YamlModel: input_text = f""" FUEL_TYPES: - NAME: fuel @@ -36,15 +38,17 @@ def ltp_oil_loaded_yaml_factory( """ - create_direct_consumers_yaml(categories, fuel_rates, rate_types, consumer_names) - yaml_text = yaml.safe_load(input_text) - configuration = PyYamlYamlModel( - internal_datamodel=yaml_text, - name="test", - instantiated_through_read=True, + configuration_service = OverridableStreamConfigurationService( + stream=ResourceStream(name="ltp_export", stream=StringIO(input_text)) + ) + resource_service = FileResourceService(working_directory=Path("dummy_path")) + + model = YamlModel( + configuration_service=configuration_service, + resource_service=resource_service, + output_frequency=Frequency.YEAR, ) - yaml_model = map_yaml_to_dto(configuration=configuration, resources={}) - return yaml_model + return model def create_direct_consumers_yaml( diff --git a/src/libecalc/fixtures/cases/ltp_export/utilities.py b/src/libecalc/fixtures/cases/ltp_export/utilities.py index 52a8c08b00..cf80b6d6d8 100644 --- a/src/libecalc/fixtures/cases/ltp_export/utilities.py +++ b/src/libecalc/fixtures/cases/ltp_export/utilities.py @@ -1,21 +1,19 @@ from datetime import datetime -from typing import List, Union +from typing import List from libecalc.application.energy_calculator import EnergyCalculator from libecalc.application.graph_result import GraphResult -from libecalc.common.time_utils import Frequency from libecalc.common.variables import VariablesMap -from libecalc.dto import Asset, Installation from libecalc.presentation.exporter.configs.configs import LTPConfig +from libecalc.presentation.yaml.model import YamlModel -def get_consumption(model: Union[Installation, Asset], variables: VariablesMap, time_vector: List[datetime]): - model = model +def get_consumption(model: YamlModel, variables: VariablesMap, time_vector: List[datetime]): graph = model.get_graph() energy_calculator = EnergyCalculator(graph=graph) - consumer_results = energy_calculator.evaluate_energy_usage(variables) - emission_results = energy_calculator.evaluate_emissions(variables, consumer_results) + consumer_results = energy_calculator.evaluate_energy_usage() + emission_results = energy_calculator.evaluate_emissions() graph_result = GraphResult( graph=graph, @@ -24,7 +22,7 @@ def get_consumption(model: Union[Installation, Asset], variables: VariablesMap, emission_results=emission_results, ) - ltp_filter = LTPConfig.filter(frequency=Frequency.YEAR) + ltp_filter = LTPConfig.filter(frequency=model.result_options.output_frequency) ltp_result = ltp_filter.filter(graph_result, time_vector) return ltp_result diff --git a/src/libecalc/fixtures/cases/venting_emitters/venting_emitter_yaml.py b/src/libecalc/fixtures/cases/venting_emitters/venting_emitter_yaml.py index 9cec2a9da5..39f1c786d5 100644 --- a/src/libecalc/fixtures/cases/venting_emitters/venting_emitter_yaml.py +++ b/src/libecalc/fixtures/cases/venting_emitters/venting_emitter_yaml.py @@ -1,12 +1,11 @@ from io import StringIO from pathlib import Path -from typing import List +from typing import Callable, List from ecalc_cli.infrastructure.file_resource_service import FileResourceService from libecalc.common.time_utils import Frequency from libecalc.common.units import Unit from libecalc.common.utils.rates import RateType -from libecalc.fixtures.case_types import DTOCase from libecalc.presentation.yaml.model import YamlModel from libecalc.presentation.yaml.yaml_entities import ResourceStream from libecalc.presentation.yaml.yaml_types.emitters.yaml_venting_emitter import ( @@ -19,13 +18,12 @@ from tests.libecalc.input.mappers.test_model_mapper import OverridableStreamConfigurationService -def venting_emitter_yaml_factory( +def venting_emitter_installation_factory( rate_types: List[RateType], units: List[YamlEmissionRateUnits], emission_names: List[str], regularity: float, names: List[str], - path: Path, emission_rates: List[float] = None, emitter_types: List[str] = None, categories: List[str] = None, @@ -36,7 +34,7 @@ def venting_emitter_yaml_factory( units_oil_rates: List[YamlOilRateUnits] = None, include_emitters: bool = True, include_fuel_consumers: bool = True, -) -> DTOCase: +) -> str: if categories is None: categories = ["STORAGE"] * len(names) if emitter_types is None: @@ -49,36 +47,41 @@ def venting_emitter_yaml_factory( units_oil_rates = [Unit.KILO_PER_DAY] * len(names) if emission_rates is None: emission_rates = [10] * len(names) + installation_yaml = f""" + - NAME: {installation_name} + HCEXPORT: 0 + FUEL: fuel + CATEGORY: FIXED + REGULARITY: {regularity} - input_text = f""" - FACILITY_INPUTS: - - NAME: generator_energy_function - FILE: '../ltp_export/data/einput/genset_17MW.csv' - TYPE: ELECTRICITY2FUEL - FUEL_TYPES: - - NAME: fuel - EMISSIONS: - - NAME: co2 - FACTOR: 2 - - START: 2027-01-01 - END: 2029-01-01 - - INSTALLATIONS: - - NAME: {installation_name} - HCEXPORT: 0 - FUEL: fuel - CATEGORY: FIXED - REGULARITY: {regularity} - - {create_fuel_consumers(include_fuel_consumers=include_fuel_consumers,)} - - {create_venting_emitters_yaml( + {create_fuel_consumers(include_fuel_consumers=include_fuel_consumers, )} + + {create_venting_emitters_yaml( categories=categories, rate_types=rate_types, emitter_names=names, emission_names=emission_names, emission_rates=emission_rates, units=units, emission_keyword_name=emission_keyword_name, include_emitters=include_emitters, emitter_types=emitter_types, oil_rates=oil_rates, emission_factors=emission_factors, units_oil_rates=units_oil_rates, )} +""" + return installation_yaml + +def get_configuration_service(installation_factories: List[Callable[[], str]]): + input_text = f""" +FACILITY_INPUTS: + - NAME: generator_energy_function + FILE: '../ltp_export/data/einput/genset_17MW.csv' + TYPE: ELECTRICITY2FUEL +FUEL_TYPES: +- NAME: fuel + EMISSIONS: + - NAME: co2 + FACTOR: 2 + +START: 2027-01-01 +END: 2029-01-01 + +INSTALLATIONS: + {''.join(installation_factory() for installation_factory in installation_factories)} """ configuration_service = OverridableStreamConfigurationService( @@ -87,12 +90,23 @@ def venting_emitter_yaml_factory( stream=StringIO(input_text), ) ) + return configuration_service + + +def venting_emitter_yaml_factory( + path: Path, + **installation_kwargs, +) -> YamlModel: + configuration_service = get_configuration_service( + [lambda: venting_emitter_installation_factory(**installation_kwargs)] + ) resource_service = FileResourceService(working_directory=path) model = YamlModel( configuration_service=configuration_service, resource_service=resource_service, output_frequency=Frequency.YEAR ) + model.validate_for_run() - return DTOCase(ecalc_model=model.dto, variables=model.variables) + return model def create_fuel_consumers(include_fuel_consumers: bool) -> str: diff --git a/src/libecalc/presentation/exporter/queries.py b/src/libecalc/presentation/exporter/queries.py index 7b725b36d0..7b2372ce4b 100644 --- a/src/libecalc/presentation/exporter/queries.py +++ b/src/libecalc/presentation/exporter/queries.py @@ -18,6 +18,7 @@ ) from libecalc.core.result import GeneratorSetResult from libecalc.expression import Expression +from libecalc.presentation.yaml.domain.components.installation_component import InstallationComponent from libecalc.presentation.yaml.yaml_types.emitters.yaml_venting_emitter import ( YamlVentingType, ) @@ -73,6 +74,7 @@ def query( frequency: Frequency, ) -> Optional[Dict[datetime, float]]: installation_dto = installation_graph.graph.get_node(installation_graph.graph.root) + assert isinstance(installation_dto, InstallationComponent) installation_time_steps = installation_graph.timesteps time_steps = resample_time_steps( @@ -80,13 +82,7 @@ def query( time_steps=installation_time_steps, ) - regularity = TimeSeriesFloat( - timesteps=installation_time_steps, - values=installation_graph.variables_map.evaluate( - expression=TemporalModel(installation_dto.regularity) - ).tolist(), - unit=Unit.NONE, - ) + regularity = installation_dto.regularity aggregated_result: DefaultDict[datetime, float] = defaultdict(float) aggregated_result_volume = {} diff --git a/src/libecalc/presentation/json_result/mapper.py b/src/libecalc/presentation/json_result/mapper.py index 5d7f35562a..138ef2bf17 100644 --- a/src/libecalc/presentation/json_result/mapper.py +++ b/src/libecalc/presentation/json_result/mapper.py @@ -48,6 +48,9 @@ PumpModelResult, TurbineModelResult, ) +from libecalc.presentation.yaml.domain.components.asset_component import AssetComponent +from libecalc.presentation.yaml.domain.components.electricity_consumer_component import ElectricityConsumerComponent +from libecalc.presentation.yaml.domain.components.fuel_consumer_component import FuelConsumerComponent def get_operational_setting_used_id(timestep: datetime, operational_settings_used: TimeSeriesInt) -> int: @@ -279,24 +282,14 @@ def _evaluate_installations( """ asset_id = graph_result.graph.root asset = graph_result.graph.get_node(asset_id) + + if not isinstance(asset, AssetComponent): + raise ProgrammingError("This should be an asset") + installation_results = [] for installation in asset.installations: - regularity = TimeSeriesFloat( - timesteps=expression_evaluator.get_time_vector(), - values=expression_evaluator.evaluate(expression=TemporalModel(installation.regularity)), - unit=Unit.NONE, - ) - hydrocarbon_export_rate = expression_evaluator.evaluate( - expression=TemporalModel(installation.hydrocarbon_export) - ) - - hydrocarbon_export_rate = TimeSeriesRate( - timesteps=expression_evaluator.get_time_vector(), - values=hydrocarbon_export_rate, - unit=Unit.STANDARD_CUBIC_METER_PER_DAY, - rate_type=RateType.CALENDAR_DAY, - regularity=regularity.values, - ) + regularity = installation.regularity + hydrocarbon_export_rate = installation.hydrocarbon_export_rate sub_components = [ graph_result.consumer_results[component_id].component_result @@ -403,7 +396,7 @@ def get_asset_result(graph_result: GraphResult) -> libecalc.presentation.json_re asset_id = graph_result.graph.root asset = graph_result.graph.get_node(asset_id) - if not isinstance(asset, libecalc.dto.Asset): + if not isinstance(asset, AssetComponent): raise ProgrammingError("Need an asset graph to get asset result") installation_results = _evaluate_installations( @@ -412,7 +405,7 @@ def get_asset_result(graph_result: GraphResult) -> libecalc.presentation.json_re ) regularities: Dict[str, TimeSeriesFloat] = { - installation.id: installation.regularity for installation in installation_results + installation.id: installation.regularity for installation in asset.installations } models = [] @@ -424,12 +417,15 @@ def get_asset_result(graph_result: GraphResult) -> libecalc.presentation.json_re parent_installation_id = graph_result.graph.get_parent_installation_id(consumer_id) regularity: TimeSeriesFloat = regularities[parent_installation_id] - if consumer_node_info.component_type in [ComponentType.COMPRESSOR, ComponentType.COMPRESSOR_SYSTEM]: - component = graph_result.graph.get_node(consumer_id) - + component = graph_result.graph.get_node(consumer_id) + if consumer_node_info.component_type in [ + ComponentType.COMPRESSOR, + ComponentType.COMPRESSOR_SYSTEM, + ] and isinstance(component, (FuelConsumerComponent, ElectricityConsumerComponent)): for model in consumer_result.models: period = Period(model.timesteps[0], model.timesteps[-1]) + # TODO: Deal with this inlet_pressure_eval = get_requested_compressor_pressures( energy_usage_model=component.energy_usage_model, pressure_type=CompressorPressureType.INLET_PRESSURE, @@ -1008,7 +1004,6 @@ def get_asset_result(graph_result: GraphResult) -> libecalc.presentation.json_re ] ) elif consumer_node_info.component_type in [ComponentType.PUMP, ComponentType.PUMP_SYSTEM]: - component = graph_result.graph.get_node(consumer_id) for model in consumer_result.models: models.extend( [ @@ -1393,17 +1388,8 @@ def get_asset_result(graph_result: GraphResult) -> libecalc.presentation.json_re sub_components.append(obj) # When only venting emitters are specified, without a generator set: the installation result - # is empty for this installation. Ensure that the installation regularity is found, even if only - # venting emitters are defined for one installation: - if len(installation_results) < len(asset.installations): - regularities = { - installation.id: TimeSeriesFloat( - values=graph_result.variables_map.evaluate(expression=TemporalModel(installation.regularity)).tolist(), - unit=Unit.NONE, - timesteps=graph_result.variables_map.get_time_vector(), - ) - for installation in asset.installations - } + # is empty for this installation. + # TODO: We should probably provide an installation result when only venting emitters are specified. time_series_zero = TimeSeriesRate( values=[0] * graph_result.variables_map.length, @@ -1415,16 +1401,17 @@ def get_asset_result(graph_result: GraphResult) -> libecalc.presentation.json_re for installation in asset.installations: for venting_emitter in installation.venting_emitters: + node_info = venting_emitter.get_node_info() energy_usage = time_series_zero sub_components.append( libecalc.presentation.json_result.result.VentingEmitterResult( - id=venting_emitter.id, - name=venting_emitter.name, - componentType=venting_emitter.component_type.value, + id=node_info.id, + name=node_info.name, + componentType=node_info.component_type.value, component_level=ComponentLevel.CONSUMER, parent=installation.id, emissions=_parse_emissions( - graph_result.emission_results[venting_emitter.id], regularities[installation.id] + graph_result.emission_results[node_info.id], regularities[installation.id] ), timesteps=graph_result.variables_map.time_vector, is_valid=TimeSeriesBoolean( diff --git a/src/libecalc/presentation/yaml/domain/components/asset_component.py b/src/libecalc/presentation/yaml/domain/components/asset_component.py new file mode 100644 index 0000000000..43b4a38cf1 --- /dev/null +++ b/src/libecalc/presentation/yaml/domain/components/asset_component.py @@ -0,0 +1,60 @@ +from typing import List + +from libecalc.common.component_info.component_level import ComponentLevel +from libecalc.common.component_type import ComponentType +from libecalc.common.time_utils import Period +from libecalc.common.variables import ExpressionEvaluator +from libecalc.dto.component_graph import ComponentGraph +from libecalc.dto.node_info import NodeInfo +from libecalc.presentation.yaml.domain.components.installation_component import InstallationComponent +from libecalc.presentation.yaml.domain.reference_service import ReferenceService +from libecalc.presentation.yaml.yaml_models.yaml_model import YamlValidator + + +class AssetComponent: + def __init__( + self, + yaml_asset: YamlValidator, + reference_service: ReferenceService, + target_period: Period, + expression_evaluator: ExpressionEvaluator, + ): + self._yaml_asset = yaml_asset + self._installations = [ + InstallationComponent( + installation, + reference_service=reference_service, + target_period=target_period, + expression_evaluator=expression_evaluator, + ) + for installation in yaml_asset.installations + ] + + @property + def id(self) -> str: + return self._yaml_asset.name + + def get_graph(self) -> ComponentGraph: + graph = ComponentGraph() + graph.add_node(self) + for installation in self._installations: + graph.add_subgraph(installation.get_graph()) + graph.add_edge(self.id, installation.id) + + return graph + + @property + def name(self) -> str: + return self._yaml_asset.name + + def get_node_info(self) -> NodeInfo: + return NodeInfo( + id=self.id, + name=self.name, + component_level=ComponentLevel.ASSET, + component_type=ComponentType.ASSET, + ) + + @property + def installations(self) -> List[InstallationComponent]: + return self._installations diff --git a/src/libecalc/presentation/yaml/domain/components/consumer_system_component.py b/src/libecalc/presentation/yaml/domain/components/consumer_system_component.py new file mode 100644 index 0000000000..4c2a3cf7d5 --- /dev/null +++ b/src/libecalc/presentation/yaml/domain/components/consumer_system_component.py @@ -0,0 +1,208 @@ +from collections import defaultdict +from datetime import datetime +from typing import Dict, List, Optional + +from pydantic import BaseModel, ConfigDict, Field + +from libecalc.common.component_info.component_level import ComponentLevel +from libecalc.common.component_type import ComponentType +from libecalc.common.priorities import Priorities, PriorityID +from libecalc.common.priority_optimizer import ComponentID, PriorityOptimizer +from libecalc.common.stream_conditions import TimeSeriesStreamConditions +from libecalc.common.string.string_utils import generate_id, to_camel_case +from libecalc.common.time_utils import Period +from libecalc.common.units import Unit +from libecalc.common.utils.rates import TimeSeriesFloat, TimeSeriesInt, TimeSeriesStreamDayRate, TimeSeriesString +from libecalc.common.variables import ExpressionEvaluator +from libecalc.core.consumers.consumer_system import ConsumerSystem +from libecalc.core.result import ComponentResult, EcalcModelResult +from libecalc.dto.component_graph import Component, ProcessGraph +from libecalc.dto.node_info import NodeInfo +from libecalc.dto.utils.validators import convert_expression +from libecalc.expression import Expression +from libecalc.presentation.yaml.domain.components.consumers.factory import create_consumer +from libecalc.presentation.yaml.domain.reference_service import ReferenceService +from libecalc.presentation.yaml.yaml_types.components.system.yaml_consumer_system import YamlConsumerSystem + + +class EcalcBaseModel(BaseModel): + model_config = ConfigDict( + extra="forbid", + alias_generator=to_camel_case, + populate_by_name=True, + ) + + +class Crossover(EcalcBaseModel): + model_config = ConfigDict(populate_by_name=True) + + stream_name: Optional[str] = Field(None) + from_component_id: str + to_component_id: str + + +class SystemComponentConditions(EcalcBaseModel): + crossover: List[Crossover] + + +class ConsumerSystemComponent(ProcessGraph, Component): + def __init__( + self, + yaml_consumer_system: YamlConsumerSystem, + reference_service: ReferenceService, + target_period: Period, + regularity: Dict[datetime, Expression], + default_fuel_reference: Optional[str], + expression_evaluator: ExpressionEvaluator, + ): + self._expression_evaluator = expression_evaluator + self._yaml_consumer_system = yaml_consumer_system + self._reference_service = reference_service + + self._consumers = [ + create_consumer( + consumer=consumer, + reference_service=reference_service, + ) + for consumer in self._yaml_consumer_system.consumers + ] + self._consumer_name_to_id_map = {consumer.name: consumer.id for consumer in self._consumers} + + self._system_result: Optional[EcalcModelResult] = None + + @property + def id(self): + return generate_id() + + @property + def name(self) -> str: + return self._yaml_consumer_system.name + + def get_node_info(self) -> NodeInfo: + return NodeInfo( + id=self.id, + name=self.name, + component_level=ComponentLevel.SYSTEM, + component_type=ComponentType.CONSUMER_SYSTEM_V2, + ) + + def get_components(self) -> List[Component]: + return [self, *self._consumers] + + def get_ecalc_model_result(self) -> EcalcModelResult: + return self._system_result + + def _evaluate_stream_conditions( + self, + ) -> Priorities[Dict[ComponentID, List[TimeSeriesStreamConditions]]]: + parsed_priorities: Priorities[Dict[ComponentID, List[TimeSeriesStreamConditions]]] = defaultdict(dict) + for priority_name, priority in self._yaml_consumer_system.stream_conditions_priorities.items(): + for consumer_name, streams_conditions in priority.items(): + parsed_priorities[priority_name][generate_id(consumer_name)] = [ + TimeSeriesStreamConditions( + id=generate_id(consumer_name, stream_name), + name="-".join([consumer_name, stream_name]), + rate=TimeSeriesStreamDayRate( + timesteps=self._expression_evaluator.get_time_vector(), + values=self._expression_evaluator.evaluate( + convert_expression(stream_conditions.rate.value) + ).tolist(), + unit=stream_conditions.rate.unit, + ) + if stream_conditions.rate is not None + else None, + pressure=TimeSeriesFloat( + timesteps=self._expression_evaluator.get_time_vector(), + values=self._expression_evaluator.evaluate( + convert_expression(stream_conditions.pressure.value) + ).tolist(), + unit=stream_conditions.pressure.unit, + ) + if stream_conditions.pressure is not None + else None, + fluid_density=TimeSeriesFloat( + timesteps=self._expression_evaluator.get_time_vector(), + values=self._expression_evaluator.evaluate( + convert_expression(stream_conditions.fluid_density.value) + ).tolist(), + unit=stream_conditions.fluid_density.unit, + ) + if stream_conditions.fluid_density is not None + else None, + ) + for stream_name, stream_conditions in streams_conditions.items() + ] + return dict(parsed_priorities) + + def _get_system_conditions(self) -> SystemComponentConditions: + if self._yaml_consumer_system.component_conditions is not None: + return SystemComponentConditions( + crossover=[ + Crossover( + from_component_id=self._consumer_name_to_id_map[crossover_stream.from_], + to_component_id=self._consumer_name_to_id_map[crossover_stream.to], + stream_name=crossover_stream.name, + ) + for crossover_stream in self._yaml_consumer_system.component_conditions.crossover + ] + if self._yaml_consumer_system.component_conditions.crossover is not None + else [], + ) + else: + return SystemComponentConditions( + crossover=[], + ) + + def evaluate(self, period: Period = None) -> None: + evaluated_stream_conditions = self._evaluate_stream_conditions() + optimizer = PriorityOptimizer() + + results_per_timestep: Dict[str, Dict[datetime, ComponentResult]] = defaultdict(dict) + priorities_used = TimeSeriesString( + timesteps=[], + values=[], + unit=Unit.NONE, + ) + + for timestep in self._expression_evaluator.get_time_vector(): + if timestep not in period: + continue + + consumer_system = ConsumerSystem( + id=self.id, + consumers=self._consumers, + component_conditions=self._get_system_conditions(), + ) + + def evaluator(priority: PriorityID): + stream_conditions_for_priority = evaluated_stream_conditions[priority] + stream_conditions_for_timestep = { + component_id: [stream_condition.for_timestep(timestep) for stream_condition in stream_conditions] + for component_id, stream_conditions in stream_conditions_for_priority.items() + } + return consumer_system.evaluate_consumers(stream_conditions_for_timestep) + + optimizer_result = optimizer.optimize( + priorities=list(evaluated_stream_conditions.keys()), + evaluator=evaluator, + ) + priorities_used.append(timestep=timestep, value=optimizer_result.priority_used) + for consumer_result in optimizer_result.priority_results: + results_per_timestep[consumer_result.id][timestep] = consumer_result + + # Convert to legacy compatible operational_settings_used + priorities_to_int_map = { + priority_name: index + 1 for index, priority_name in enumerate(evaluated_stream_conditions.keys()) + } + operational_settings_used = TimeSeriesInt( + timesteps=priorities_used.timesteps, + values=[priorities_to_int_map[priority_name] for priority_name in priorities_used.values], + unit=priorities_used.unit, + ) + + system_result = ConsumerSystem.get_system_result( + id=self.id, + consumer_results=[consumer.get_ecalc_model_result() for consumer in self._consumers], + operational_settings_used=operational_settings_used, + ) + self._system_result = system_result diff --git a/src/libecalc/presentation/yaml/domain/components/consumers/compressor.py b/src/libecalc/presentation/yaml/domain/components/consumers/compressor.py new file mode 100644 index 0000000000..3698eca17f --- /dev/null +++ b/src/libecalc/presentation/yaml/domain/components/consumers/compressor.py @@ -0,0 +1,151 @@ +from datetime import datetime +from typing import Dict, List + +import numpy as np + +from libecalc.common.component_info.component_level import ComponentLevel +from libecalc.common.component_type import ComponentType +from libecalc.common.stream_conditions import TimeSeriesStreamConditions +from libecalc.common.string.string_utils import generate_id +from libecalc.common.temporal_model import TemporalModel +from libecalc.common.time_utils import Period, define_time_model_for_period +from libecalc.common.units import Unit +from libecalc.common.utils.rates import TimeSeriesBoolean, TimeSeriesFloat, TimeSeriesStreamDayRate +from libecalc.core.consumers.base import BaseConsumerWithoutOperationalSettings +from libecalc.core.models.compressor import CompressorModel, create_compressor_model +from libecalc.core.result import CompressorModelResult, CompressorResult, EcalcModelResult +from libecalc.domain.stream_conditions import StreamConditions +from libecalc.dto.component_graph import Component, ComponentID +from libecalc.dto.node_info import NodeInfo +from libecalc.presentation.yaml.domain.reference_service import ReferenceService +from libecalc.presentation.yaml.yaml_types.components.yaml_compressor import YamlCompressor + + +class Compressor(Component, BaseConsumerWithoutOperationalSettings): + def __init__(self, yaml_compressor: YamlCompressor, reference_service: ReferenceService): + self._yaml_compressor = yaml_compressor + self.reference_service = reference_service + + self._ecalc_model_results: Dict[datetime, EcalcModelResult] = {} + + @property + def id(self) -> ComponentID: + return generate_id(self._yaml_compressor.name) + + @property + def name(self) -> str: + return self._yaml_compressor.name + + def get_node_info(self) -> NodeInfo: + return NodeInfo( + id=self.id, + name=self.name, + component_level=ComponentLevel.CONSUMER, + component_type=ComponentType.COMPRESSOR_V2, + ) + + def get_ecalc_model_result(self) -> EcalcModelResult: + first_result, *rest_results = list(self._ecalc_model_results.values()) + return first_result.merge(*rest_results) + + def _get_compressor_model(self, timestep: datetime) -> CompressorModel: + model_reference_for_timestep = TemporalModel( + define_time_model_for_period(self._yaml_compressor.energy_usage_model, Period()) + ).get_model(timestep) + return create_compressor_model(self.reference_service.get_compressor_model(model_reference_for_timestep)) + + def get_max_rate(self, inlet_stream: StreamConditions, target_pressure: TimeSeriesFloat) -> List[float]: + compressor_model = self._get_compressor_model(inlet_stream.timestep) + return compressor_model.get_max_standard_rate( + suction_pressures=np.asarray([inlet_stream.pressure.value]), + discharge_pressures=np.asarray([target_pressure.value]), + ).tolist()[0] + + def evaluate(self, streams: List[StreamConditions]) -> EcalcModelResult: + timestep = streams[0].timestep + compressor_model = self._get_compressor_model(timestep) + inlet_streams = streams[:-1] + outlet_stream = streams[-1] + + model_result = compressor_model.evaluate_streams( + inlet_streams=inlet_streams, + outlet_stream=outlet_stream, + ) + + # Mixing all input rates to get total rate passed through compressor. Used when reporting streams. + total_requested_inlet_stream = StreamConditions.mix_all(inlet_streams) + total_requested_inlet_stream.name = "Total inlet" + current_timestep = total_requested_inlet_stream.timestep + + outlet_stream.rate = total_requested_inlet_stream.rate + + energy_usage = TimeSeriesStreamDayRate( + values=model_result.energy_usage, + timesteps=[current_timestep], + unit=model_result.energy_usage_unit, + ) + + component_result = CompressorResult( + timesteps=[current_timestep], + power=TimeSeriesStreamDayRate( + values=model_result.power, + timesteps=[current_timestep], + unit=model_result.power_unit, + ).fill_nan(0.0), + energy_usage=energy_usage.fill_nan(0.0), + is_valid=TimeSeriesBoolean(values=model_result.is_valid, timesteps=[current_timestep], unit=Unit.NONE), + id=self.id, + recirculation_loss=TimeSeriesStreamDayRate( + values=model_result.recirculation_loss, + timesteps=[current_timestep], + unit=Unit.MEGA_WATT, + ), + rate_exceeds_maximum=TimeSeriesBoolean( + values=model_result.rate_exceeds_maximum, + timesteps=[current_timestep], + unit=Unit.NONE, + ), + streams=[ + TimeSeriesStreamConditions.from_stream_condition(total_requested_inlet_stream), + *[ + TimeSeriesStreamConditions.from_stream_condition(inlet_stream_conditions) + for inlet_stream_conditions in inlet_streams + ], + TimeSeriesStreamConditions.from_stream_condition(outlet_stream), + ], + ) + + ecalc_model_result = EcalcModelResult( + component_result=component_result, + sub_components=[], + models=[ + CompressorModelResult( + name="N/A", # No context available to populate model name + timesteps=[current_timestep], + is_valid=TimeSeriesBoolean( + timesteps=[current_timestep], + values=model_result.is_valid, + unit=Unit.NONE, + ), + power=TimeSeriesStreamDayRate( + timesteps=[current_timestep], + values=model_result.power, + unit=model_result.power_unit, + ) + if model_result.power is not None + else None, + energy_usage=TimeSeriesStreamDayRate( + timesteps=[current_timestep], + values=model_result.energy_usage, + unit=model_result.energy_usage_unit, + ), + rate_sm3_day=model_result.rate_sm3_day, + stage_results=model_result.stage_results, + failure_status=model_result.failure_status, + inlet_stream_condition=model_result.inlet_stream_condition, + outlet_stream_condition=model_result.outlet_stream_condition, + ) + ], + ) + self._ecalc_model_results[timestep] = ecalc_model_result + return ecalc_model_result diff --git a/src/libecalc/presentation/yaml/domain/components/consumers/factory.py b/src/libecalc/presentation/yaml/domain/components/consumers/factory.py new file mode 100644 index 0000000000..037db623db --- /dev/null +++ b/src/libecalc/presentation/yaml/domain/components/consumers/factory.py @@ -0,0 +1,39 @@ +from typing import Union, assert_never, overload + +from libecalc.presentation.yaml.domain.components.consumers.compressor import Compressor +from libecalc.presentation.yaml.domain.components.consumers.pump import Pump +from libecalc.presentation.yaml.domain.reference_service import ReferenceService +from libecalc.presentation.yaml.yaml_types.components.yaml_compressor import YamlCompressor +from libecalc.presentation.yaml.yaml_types.components.yaml_pump import YamlPump + + +@overload +def create_consumer( + consumer: YamlCompressor, + reference_service: ReferenceService, +) -> Compressor: ... + + +@overload +def create_consumer( + consumer: YamlPump, + reference_service: ReferenceService, +) -> Pump: ... + + +def create_consumer( + consumer: Union[YamlCompressor, YamlPump], + reference_service: ReferenceService, +) -> Union[Compressor, Pump]: + if isinstance(consumer, YamlCompressor): + return Compressor( + yaml_compressor=consumer, + reference_service=reference_service, + ) + elif isinstance(consumer, YamlPump): + return Pump( + yaml_pump=consumer, + reference_service=reference_service, + ) + else: + assert_never(consumer) diff --git a/src/libecalc/presentation/yaml/domain/components/consumers/pump.py b/src/libecalc/presentation/yaml/domain/components/consumers/pump.py new file mode 100644 index 0000000000..258063ee82 --- /dev/null +++ b/src/libecalc/presentation/yaml/domain/components/consumers/pump.py @@ -0,0 +1,160 @@ +from datetime import datetime +from typing import Dict, List + +import numpy as np + +from libecalc.common.component_info.component_level import ComponentLevel +from libecalc.common.component_type import ComponentType +from libecalc.common.stream_conditions import TimeSeriesStreamConditions +from libecalc.common.string.string_utils import generate_id +from libecalc.common.temporal_model import TemporalModel +from libecalc.common.time_utils import Period, define_time_model_for_period +from libecalc.common.units import Unit +from libecalc.common.utils.rates import TimeSeriesBoolean, TimeSeriesFloat, TimeSeriesStreamDayRate +from libecalc.core.consumers.base import BaseConsumerWithoutOperationalSettings +from libecalc.core.models.pump import PumpModel, create_pump_model +from libecalc.core.result import EcalcModelResult +from libecalc.core.result.results import PumpModelResult, PumpResult +from libecalc.domain.stream_conditions import StreamConditions +from libecalc.dto.component_graph import Component, ComponentID +from libecalc.dto.node_info import NodeInfo +from libecalc.presentation.yaml.domain.reference_service import ReferenceService +from libecalc.presentation.yaml.yaml_types.components.yaml_pump import YamlPump + + +class Pump(Component, BaseConsumerWithoutOperationalSettings): + def __init__(self, yaml_pump: YamlPump, reference_service: ReferenceService): + self._yaml_pump = yaml_pump + self.reference_service = reference_service + + self._ecalc_model_results: Dict[datetime, EcalcModelResult] = {} + + @property + def id(self) -> ComponentID: + return generate_id(self._yaml_pump.name) + + @property + def name(self) -> str: + return self._yaml_pump.name + + def get_node_info(self) -> NodeInfo: + return NodeInfo( + id=self.id, + name=self.name, + component_level=ComponentLevel.CONSUMER, + component_type=ComponentType.PUMP_V2, + ) + + def get_ecalc_model_result(self) -> EcalcModelResult: + first_result, *rest_results = list(self._ecalc_model_results.values()) + return first_result.merge(*rest_results) + + def _get_pump_model(self, timestep: datetime) -> PumpModel: + model_reference_for_timestep = TemporalModel( + define_time_model_for_period(self._yaml_pump.energy_usage_model, Period()) + ).get_model(timestep) + return create_pump_model(self.reference_service.get_pump_model(model_reference_for_timestep)) + + def get_max_rate(self, inlet_stream: StreamConditions, target_pressure: TimeSeriesFloat) -> List[float]: + return ( + self._get_pump_model(inlet_stream.timestep) + .get_max_standard_rate( + suction_pressures=np.asarray([inlet_stream.pressure.value]), + discharge_pressures=np.asarray([target_pressure.value]), + fluid_density=np.asarray([inlet_stream.density.value]), + ) + .tolist()[0] + ) + + def evaluate(self, streams: List[StreamConditions]) -> EcalcModelResult: + timestep = streams[0].timestep + inlet_streams = streams[:-1] + outlet_stream = streams[-1] + + model_result = self._get_pump_model(timestep).evaluate_streams( + inlet_streams=inlet_streams, + outlet_stream=outlet_stream, + ) + + # Mixing all input rates to get total rate passed through compressor. Used when reporting streams. + total_requested_inlet_stream = StreamConditions.mix_all(inlet_streams) + total_requested_inlet_stream.name = "Total inlet" + current_timestep = total_requested_inlet_stream.timestep + + outlet_stream.rate = total_requested_inlet_stream.rate + + component_result = PumpResult( + id=self.id, + timesteps=[current_timestep], + power=TimeSeriesStreamDayRate( + values=model_result.power, + timesteps=[current_timestep], + unit=model_result.power_unit, + ).fill_nan(0.0), + energy_usage=TimeSeriesStreamDayRate( + values=model_result.energy_usage, + timesteps=[current_timestep], + unit=model_result.energy_usage_unit, + ).fill_nan(0.0), + inlet_liquid_rate_m3_per_day=TimeSeriesStreamDayRate( + values=model_result.rate, + timesteps=[current_timestep], + unit=Unit.STANDARD_CUBIC_METER_PER_DAY, + ), + inlet_pressure_bar=TimeSeriesFloat( + values=model_result.suction_pressure, + timesteps=[current_timestep], + unit=Unit.BARA, + ), + outlet_pressure_bar=TimeSeriesFloat( + values=model_result.discharge_pressure, + timesteps=[current_timestep], + unit=Unit.BARA, + ), + operational_head=TimeSeriesFloat( + values=model_result.operational_head, + timesteps=[current_timestep], + unit=Unit.POLYTROPIC_HEAD_KILO_JOULE_PER_KG, + ), + is_valid=TimeSeriesBoolean(values=model_result.is_valid, timesteps=[current_timestep], unit=Unit.NONE), + streams=[ + TimeSeriesStreamConditions.from_stream_condition(total_requested_inlet_stream), + *[ + TimeSeriesStreamConditions.from_stream_condition(inlet_stream_conditions) + for inlet_stream_conditions in inlet_streams + ], + TimeSeriesStreamConditions.from_stream_condition(outlet_stream), + ], + ) + + return EcalcModelResult( + component_result=component_result, + sub_components=[], + models=[ + PumpModelResult( + name="N/A", # No context available to populate model name + timesteps=[current_timestep], + is_valid=TimeSeriesBoolean( + timesteps=[current_timestep], + values=model_result.is_valid, + unit=Unit.NONE, + ), + power=TimeSeriesStreamDayRate( + timesteps=[current_timestep], + values=model_result.power, + unit=model_result.power_unit, + ) + if model_result.power is not None + else None, + energy_usage=TimeSeriesStreamDayRate( + timesteps=[current_timestep], + values=model_result.energy_usage, + unit=model_result.energy_usage_unit, + ), + inlet_liquid_rate_m3_per_day=model_result.rate, + inlet_pressure_bar=model_result.suction_pressure, + outlet_pressure_bar=model_result.discharge_pressure, + operational_head=model_result.operational_head, + ) + ], + ) diff --git a/src/libecalc/presentation/yaml/domain/components/electricity_consumer_component.py b/src/libecalc/presentation/yaml/domain/components/electricity_consumer_component.py new file mode 100644 index 0000000000..b26d973c27 --- /dev/null +++ b/src/libecalc/presentation/yaml/domain/components/electricity_consumer_component.py @@ -0,0 +1,98 @@ +from datetime import datetime +from typing import Dict, Optional + +from typing_extensions import deprecated + +from libecalc.common.component_info.component_level import ComponentLevel +from libecalc.common.component_type import ComponentType +from libecalc.common.consumption_type import ConsumptionType +from libecalc.common.errors.exceptions import ProgrammingError +from libecalc.common.graph import NodeID +from libecalc.common.string.string_utils import generate_id +from libecalc.common.temporal_model import TemporalModel +from libecalc.common.time_utils import Period +from libecalc.common.utils.rates import TimeSeriesStreamDayRate +from libecalc.common.variables import ExpressionEvaluator +from libecalc.core.consumers.legacy_consumer.component import Consumer +from libecalc.core.consumers.legacy_consumer.consumer_function_mapper import EnergyModelMapper +from libecalc.core.result import EcalcModelResult +from libecalc.core.result.emission import EmissionResult +from libecalc.dto import ElectricEnergyUsageModel, ElectricityConsumer +from libecalc.dto.component_graph import PowerConsumer +from libecalc.dto.node_info import NodeInfo +from libecalc.expression import Expression +from libecalc.presentation.yaml.domain.reference_service import ReferenceService +from libecalc.presentation.yaml.mappers.component_mapper import ConsumerMapper +from libecalc.presentation.yaml.yaml_types.components.legacy.yaml_electricity_consumer import YamlElectricityConsumer + + +class ElectricityConsumerComponent(PowerConsumer): + def __init__( + self, + yaml_fuel_consumer: YamlElectricityConsumer, + reference_service: ReferenceService, + target_period: Period, + regularity: Dict[datetime, Expression], + default_fuel_reference: Optional[str], + expression_evaluator: ExpressionEvaluator, + ): + self._expression_evaluator = expression_evaluator + self._yaml_consumer = yaml_fuel_consumer + consumer_mapper = ConsumerMapper(references=reference_service, target_period=target_period) + self._dto_consumer: ElectricityConsumer = consumer_mapper.from_yaml_to_dto( + yaml_fuel_consumer, + regularity=regularity, + consumes=ConsumptionType.ELECTRICITY, + default_fuel=default_fuel_reference, + ) + self._core_consumer = Consumer( + id=self.id, + name=self.name, + component_type=self.get_node_info().component_type, + regularity=TemporalModel(self._dto_consumer.regularity), + consumes=ConsumptionType.ELECTRICITY, + energy_usage_model=TemporalModel( + { + start_time: EnergyModelMapper.from_dto_to_domain(model) + for start_time, model in self._dto_consumer.energy_usage_model.items() + } + ), + ) + + # Keep results when calculated + self._ecalc_model_result: Optional[EcalcModelResult] = None + self._emissions: Optional[Dict[str, EmissionResult]] = None + + @property + def id(self) -> NodeID: + return generate_id(self._yaml_consumer.name) + + @property + def name(self) -> str: + return self._yaml_consumer.name + + def get_node_info(self) -> NodeInfo: + return NodeInfo( + id=self.id, + name=self.name, + component_level=ComponentLevel.CONSUMER + if self._dto_consumer.component_type not in [ComponentType.COMPRESSOR_SYSTEM, ComponentType.PUMP_SYSTEM] + else ComponentLevel.SYSTEM, + component_type=self._dto_consumer.component_type, + ) + + def get_power_requirement(self, period: Period = None) -> TimeSeriesStreamDayRate: + consumer_result = self._core_consumer.evaluate(self._expression_evaluator) + self._ecalc_model_result = consumer_result + return consumer_result.component_result.power + + def get_ecalc_model_result(self) -> EcalcModelResult: + if self._ecalc_model_result is None: + raise ProgrammingError("Propagate streams first") + + return self._ecalc_model_result + + @property + @deprecated("We don't want to expose the dto directly, instead implement an interface with behaviour") + def energy_usage_model(self) -> Dict[datetime, ElectricEnergyUsageModel]: + return self._dto_consumer.energy_usage_model diff --git a/src/libecalc/presentation/yaml/domain/components/fuel_consumer_component.py b/src/libecalc/presentation/yaml/domain/components/fuel_consumer_component.py new file mode 100644 index 0000000000..776e5948e0 --- /dev/null +++ b/src/libecalc/presentation/yaml/domain/components/fuel_consumer_component.py @@ -0,0 +1,110 @@ +from datetime import datetime +from typing import Dict, Optional + +import numpy as np +from typing_extensions import deprecated + +from libecalc.common.component_info.component_level import ComponentLevel +from libecalc.common.component_type import ComponentType +from libecalc.common.consumption_type import ConsumptionType +from libecalc.common.errors.exceptions import ProgrammingError +from libecalc.common.graph import NodeID +from libecalc.common.string.string_utils import generate_id +from libecalc.common.temporal_model import TemporalModel +from libecalc.common.time_utils import Period +from libecalc.common.utils.rates import TimeSeriesStreamDayRate +from libecalc.common.variables import ExpressionEvaluator +from libecalc.core.consumers.legacy_consumer.component import Consumer +from libecalc.core.consumers.legacy_consumer.consumer_function_mapper import EnergyModelMapper +from libecalc.core.models.fuel import FuelModel +from libecalc.core.result import EcalcModelResult +from libecalc.core.result.emission import EmissionResult +from libecalc.dto import FuelEnergyUsageModel +from libecalc.dto.component_graph import FuelConsumer +from libecalc.dto.node_info import NodeInfo +from libecalc.expression import Expression +from libecalc.presentation.yaml.domain.reference_service import ReferenceService +from libecalc.presentation.yaml.mappers.component_mapper import ConsumerMapper +from libecalc.presentation.yaml.yaml_types.components.legacy.yaml_fuel_consumer import YamlFuelConsumer + + +class FuelConsumerComponent(FuelConsumer): + def __init__( + self, + yaml_fuel_consumer: YamlFuelConsumer, + reference_service: ReferenceService, + target_period: Period, + regularity: Dict[datetime, Expression], + default_fuel_reference: Optional[str], + expression_evaluator: ExpressionEvaluator, + ): + self._expression_evaluator = expression_evaluator + self._yaml_consumer = yaml_fuel_consumer + consumer_mapper = ConsumerMapper(references=reference_service, target_period=target_period) + + self._dto_consumer = consumer_mapper.from_yaml_to_dto( + yaml_fuel_consumer, + regularity=regularity, + consumes=ConsumptionType.FUEL, + default_fuel=default_fuel_reference, + ) + self._core_consumer = Consumer( + id=self.id, + name=self.name, + component_type=self.get_node_info().component_type, + regularity=TemporalModel(self._dto_consumer.regularity), + consumes=ConsumptionType.FUEL, + energy_usage_model=TemporalModel( + { + start_time: EnergyModelMapper.from_dto_to_domain(model) + for start_time, model in self._dto_consumer.energy_usage_model.items() + } + ), + ) + + # Keep results when calculated + self._ecalc_model_result: Optional[EcalcModelResult] = None + self._emissions: Optional[Dict[str, EmissionResult]] = None + + @property + def id(self) -> NodeID: + return generate_id(self._yaml_consumer.name) + + @property + def name(self) -> str: + return self._yaml_consumer.name + + def get_node_info(self) -> NodeInfo: + return NodeInfo( + id=self.id, + name=self.name, + component_level=ComponentLevel.CONSUMER + if self._dto_consumer.component_type not in [ComponentType.COMPRESSOR_SYSTEM, ComponentType.PUMP_SYSTEM] + else ComponentLevel.SYSTEM, + component_type=self._dto_consumer.component_type, + ) + + def get_emissions(self, period: Period = None) -> Dict[str, EmissionResult]: + fuel_model = FuelModel(self._dto_consumer.fuel) + energy_usage = self.get_ecalc_model_result().component_result.energy_usage + self._emissions = fuel_model.evaluate_emissions( + expression_evaluator=self._expression_evaluator, + fuel_rate=np.asarray(energy_usage.values), + ) + return self._emissions + + def get_fuel_usage(self, period: Period = None) -> TimeSeriesStreamDayRate: + consumer_result = self._core_consumer.evaluate(expression_evaluator=self._expression_evaluator) + self._ecalc_model_result = consumer_result + return consumer_result.component_result.energy_usage + + def get_ecalc_model_result(self) -> EcalcModelResult: + if self._ecalc_model_result is None: + raise ProgrammingError("Calculate fuel usage first") + + return self._ecalc_model_result + + @property + @deprecated("We don't want to expose the dto directly, instead implement an interface with behaviour") + def energy_usage_model(self) -> Dict[datetime, FuelEnergyUsageModel]: + return self._dto_consumer.energy_usage_model diff --git a/src/libecalc/presentation/yaml/domain/components/generator_set_component.py b/src/libecalc/presentation/yaml/domain/components/generator_set_component.py new file mode 100644 index 0000000000..711345d7e0 --- /dev/null +++ b/src/libecalc/presentation/yaml/domain/components/generator_set_component.py @@ -0,0 +1,145 @@ +import operator +from datetime import datetime +from functools import reduce +from typing import Dict, List, Optional + +import numpy as np + +from libecalc.common.component_info.component_level import ComponentLevel +from libecalc.common.component_type import ComponentType +from libecalc.common.errors.exceptions import ProgrammingError +from libecalc.common.graph import NodeID +from libecalc.common.string.string_utils import generate_id +from libecalc.common.temporal_model import TemporalModel +from libecalc.common.time_utils import Period +from libecalc.common.units import Unit +from libecalc.common.utils.rates import TimeSeriesStreamDayRate +from libecalc.common.variables import ExpressionEvaluator +from libecalc.core.consumers.generator_set import Genset +from libecalc.core.models.fuel import FuelModel +from libecalc.core.models.generator import GeneratorModelSampled +from libecalc.core.result import EcalcModelResult +from libecalc.core.result.emission import EmissionResult +from libecalc.dto.component_graph import ComponentGraph, Emitter, PowerProvider +from libecalc.dto.node_info import NodeInfo +from libecalc.expression import Expression +from libecalc.presentation.yaml.domain.components.electricity_consumer_component import ElectricityConsumerComponent +from libecalc.presentation.yaml.domain.reference_service import ReferenceService +from libecalc.presentation.yaml.mappers.component_mapper import GeneratorSetMapper +from libecalc.presentation.yaml.yaml_types.components.yaml_generator_set import YamlGeneratorSet + + +class GeneratorSetComponent(PowerProvider, Emitter): + def __init__( + self, + yaml_generator_set: YamlGeneratorSet, + reference_service: ReferenceService, + target_period: Period, + regularity: Dict[datetime, Expression], + default_fuel_reference: Optional[str], + expression_evaluator: ExpressionEvaluator, + ): + self._expression_evaluator = expression_evaluator + self._yaml_generator_set = yaml_generator_set + generator_set_mapper = GeneratorSetMapper(references=reference_service, target_period=target_period) + self._dto_generator_set = generator_set_mapper.from_yaml_to_dto( + yaml_generator_set, + regularity=regularity, + default_fuel=default_fuel_reference, + ) + self._core_generator_set = Genset( + id=self.id, + name=self.name, + temporal_generator_set_model=TemporalModel( + { + start_time: GeneratorModelSampled( + fuel_values=model.fuel_values, + power_values=model.power_values, + energy_usage_adjustment_constant=model.energy_usage_adjustment_constant, + energy_usage_adjustment_factor=model.energy_usage_adjustment_factor, + ) + for start_time, model in self._dto_generator_set.generator_set_model.items() + } + ), + ) + + self._electricity_consumers = [ + ElectricityConsumerComponent( + electricity_consumer, + reference_service=reference_service, + target_period=target_period, + regularity=regularity, + default_fuel_reference=default_fuel_reference, + expression_evaluator=expression_evaluator, + ) + for electricity_consumer in self._yaml_generator_set.consumers + ] + + self._ecalc_model_result: Optional[EcalcModelResult] = None + self._emissions: Optional[Dict[str, EmissionResult]] = None + + @property + def id(self) -> NodeID: + return generate_id(self.name) + + @property + def name(self) -> str: + return self._yaml_generator_set.name + + def get_graph(self) -> ComponentGraph: + graph = ComponentGraph() + graph.add_node(self) + for electricity_consumer in self._electricity_consumers: + if hasattr(electricity_consumer, "get_graph"): + graph.add_subgraph(electricity_consumer.get_graph()) + else: + graph.add_node(electricity_consumer) + + graph.add_edge(self.id, electricity_consumer.id) + + return graph + + def get_node_info(self) -> NodeInfo: + return NodeInfo( + id=self.id, + name=self.name, + component_level=ComponentLevel.GENERATOR_SET, + component_type=ComponentType.GENERATOR_SET, + ) + + def get_emissions(self, period: Period = None) -> Optional[Dict[str, EmissionResult]]: + fuel_model = FuelModel(self._dto_generator_set.fuel) + energy_usage = self.get_ecalc_model_result().component_result.energy_usage + self._emissions = fuel_model.evaluate_emissions( + expression_evaluator=self._expression_evaluator, + fuel_rate=np.asarray(energy_usage.values), + ) + return self._emissions + + def provide_power(self, power_requirement: List[TimeSeriesStreamDayRate], period: Period = None): + number_of_periods = len(self._expression_evaluator.get_time_vector()) + + aggregated_power_requirement = reduce( + operator.add, + power_requirement, + TimeSeriesStreamDayRate( + values=[0.0] * number_of_periods, + timesteps=self._expression_evaluator.get_time_vector(), + unit=Unit.MEGA_WATT, + ), # Initial value, handle no power output from components + ) + + self._ecalc_model_result = EcalcModelResult( + component_result=self._core_generator_set.evaluate( + expression_evaluator=self._expression_evaluator, + power_requirement=np.asarray(aggregated_power_requirement.values), + ), + models=[], + sub_components=[], + ) + + def get_ecalc_model_result(self) -> EcalcModelResult: + if self._ecalc_model_result is None: + raise ProgrammingError("Provide power first") + + return self._ecalc_model_result diff --git a/src/libecalc/presentation/yaml/domain/components/installation_component.py b/src/libecalc/presentation/yaml/domain/components/installation_component.py new file mode 100644 index 0000000000..a09badaaf8 --- /dev/null +++ b/src/libecalc/presentation/yaml/domain/components/installation_component.py @@ -0,0 +1,146 @@ +from typing import List + +from libecalc.common.component_info.component_level import ComponentLevel +from libecalc.common.component_type import ComponentType +from libecalc.common.string.string_utils import generate_id +from libecalc.common.time_utils import Period, define_time_model_for_period +from libecalc.common.units import Unit +from libecalc.common.utils.rates import RateType, TimeSeriesFloat, TimeSeriesRate +from libecalc.common.variables import ExpressionEvaluator +from libecalc.dto.component_graph import Component, ComponentGraph +from libecalc.dto.components import Consumer +from libecalc.dto.node_info import NodeInfo +from libecalc.dto.utils.validators import convert_expression +from libecalc.presentation.yaml.domain.components.fuel_consumer_component import FuelConsumerComponent +from libecalc.presentation.yaml.domain.components.generator_set_component import GeneratorSetComponent +from libecalc.presentation.yaml.domain.components.venting_emitter_component import VentingEmitter +from libecalc.presentation.yaml.domain.reference_service import ReferenceService +from libecalc.presentation.yaml.mappers.component_mapper import GeneratorSetMapper, InstallationMapper +from libecalc.presentation.yaml.yaml_types.components.yaml_installation import YamlInstallation + + +class InstallationComponent: + def __init__( + self, + yaml_installation: YamlInstallation, + reference_service: ReferenceService, + target_period: Period, + expression_evaluator: ExpressionEvaluator, + ): + self._target_period = target_period + self._expression_evaluator = expression_evaluator + self._yaml_installation = yaml_installation + self._dto_installation = InstallationMapper( + references=reference_service, target_period=target_period + ).from_yaml_to_dto(yaml_installation) + + self.__generator_set_mapper = GeneratorSetMapper(references=reference_service, target_period=target_period) + fuel_data = yaml_installation.fuel + regularity = define_time_model_for_period( + convert_expression(yaml_installation.regularity or 1), target_period=target_period + ) + + self._generator_sets = [ + GeneratorSetComponent( + yaml_generator_set=generator_set, + reference_service=reference_service, + target_period=target_period, + regularity=regularity, + default_fuel_reference=fuel_data, + expression_evaluator=expression_evaluator, + ) + for generator_set in yaml_installation.generator_sets or [] + ] + self._fuel_consumers: List[Consumer] = [ + FuelConsumerComponent( + yaml_fuel_consumer=fuel_consumer, + reference_service=reference_service, + target_period=target_period, + regularity=regularity, + default_fuel_reference=fuel_data, + expression_evaluator=expression_evaluator, + ) + for fuel_consumer in yaml_installation.fuel_consumers or [] + ] + + self._venting_emitters: List[VentingEmitter] = [ + VentingEmitter( + yaml_venting_emitter=venting_emitter, + regularity=regularity, + expression_evaluator=expression_evaluator, + ) + for venting_emitter in yaml_installation.venting_emitters or [] + ] + + @property + def id(self) -> str: + return generate_id(self._yaml_installation.name) + + def get_graph(self) -> ComponentGraph: + graph = ComponentGraph() + graph.add_node(self) + for component in self._fuel_consumers: + if hasattr(component, "get_graph"): + graph.add_subgraph(component.get_graph()) + else: + graph.add_node(component) + + graph.add_edge(self.id, component.id) + + for component in self._generator_sets: + if hasattr(component, "get_graph"): + graph.add_subgraph(component.get_graph()) + else: + graph.add_node(component) + + graph.add_edge(self.id, component.id) + + for component in self._venting_emitters: + if hasattr(component, "get_graph"): + graph.add_subgraph(component.get_graph()) + else: + graph.add_node(component) + + graph.add_edge(self.id, component.id) + + return graph + + @property + def name(self) -> str: + return self._yaml_installation.name + + @property + def regularity(self) -> TimeSeriesFloat: + return TimeSeriesFloat( + timesteps=self._expression_evaluator.get_time_vector(), + values=self._expression_evaluator.evaluate(convert_expression(self._yaml_installation.regularity)).tolist(), + unit=Unit.NONE, + ) + + @property + def hydrocarbon_export_rate(self) -> TimeSeriesRate: + return TimeSeriesRate( + timesteps=self._expression_evaluator.get_time_vector(), + values=self._expression_evaluator.evaluate( + convert_expression(self._yaml_installation.hydrocarbon_export) + ).tolist(), + unit=Unit.STANDARD_CUBIC_METER_PER_DAY, + rate_type=RateType.CALENDAR_DAY, + regularity=self.regularity.values, + ) + + def get_node_info(self) -> NodeInfo: + return NodeInfo( + id=self.id, + name=self.name, + component_level=ComponentLevel.INSTALLATION, + component_type=ComponentType.INSTALLATION, + ) + + @property + def venting_emitters(self) -> List[Component]: + return self._venting_emitters + + @property + def fuel_consumers(self): + return diff --git a/src/libecalc/presentation/yaml/domain/components/venting_emitter_component.py b/src/libecalc/presentation/yaml/domain/components/venting_emitter_component.py new file mode 100644 index 0000000000..c767324efc --- /dev/null +++ b/src/libecalc/presentation/yaml/domain/components/venting_emitter_component.py @@ -0,0 +1,111 @@ +from datetime import datetime +from typing import Dict, Optional + +import numpy as np + +from libecalc.common.component_info.component_level import ComponentLevel +from libecalc.common.component_type import ComponentType +from libecalc.common.string.string_utils import generate_id +from libecalc.common.time_utils import Period +from libecalc.common.units import Unit +from libecalc.common.utils.rates import Rates, RateType, TimeSeriesFloat, TimeSeriesStreamDayRate +from libecalc.common.variables import ExpressionEvaluator +from libecalc.core.result import EcalcModelResult +from libecalc.core.result.emission import EmissionResult +from libecalc.dto.component_graph import Emitter +from libecalc.dto.node_info import NodeInfo +from libecalc.dto.utils.validators import convert_expression +from libecalc.expression import Expression +from libecalc.presentation.yaml.yaml_types.emitters.yaml_venting_emitter import YamlVentingEmitter + + +class VentingEmitter(Emitter): + def __init__( + self, + yaml_venting_emitter: YamlVentingEmitter, + regularity: Dict[datetime, Expression], + expression_evaluator: ExpressionEvaluator, + ): + self._expression_evaluator = expression_evaluator + self._yaml_venting_emitter = yaml_venting_emitter + self._regularity = regularity + + @property + def id(self): + return generate_id(self._yaml_venting_emitter.name) + + def get_node_info(self) -> NodeInfo: + return NodeInfo( + id=self.id, + name=self.name, + component_level=ComponentLevel.CONSUMER, + component_type=ComponentType.VENTING_EMITTER, + ) + + @property + def name(self): + return self._yaml_venting_emitter.name + + def get_emissions(self, period: Period = None) -> Dict[str, EmissionResult]: + regularity_evaluated = self._expression_evaluator.evaluate(convert_expression(self._regularity)).tolist() + oil_rates = self._expression_evaluator.evaluate( + convert_expression(self._yaml_venting_emitter.volume.rate.value) + ).tolist() + + if self._yaml_venting_emitter.volume.rate.type == RateType.CALENDAR_DAY: + oil_rates = Rates.to_stream_day( + calendar_day_rates=np.asarray(oil_rates), + regularity=regularity_evaluated, + ).tolist() + + emissions = {} + for emission in self._yaml_venting_emitter.volume.emissions: + factors = self._expression_evaluator.evaluate(convert_expression(emission.emission_factor)) + unit = self._yaml_venting_emitter.volume.rate.unit.to_unit() + oil_rates = unit.to(Unit.STANDARD_CUBIC_METER_PER_DAY)(oil_rates) + emission_rate = [oil_rate * factor for oil_rate, factor in zip(oil_rates, factors)] + + # Emission factor is kg/Sm3 and oil rate/volume is Sm3/d. Hence, the emission rate is in kg/d: + emission_rate = Unit.KILO_PER_DAY.to(Unit.TONS_PER_DAY)(emission_rate) + + emissions[emission.name] = TimeSeriesStreamDayRate( + timesteps=self._expression_evaluator.get_time_vector(), + values=emission_rate, + unit=Unit.TONS_PER_DAY, + ) + venting_emitter_results = {} + for emission_name, emission_rate in emissions.items(): + emission_result = EmissionResult( + name=emission_name, + timesteps=self._expression_evaluator.get_time_vector(), + rate=emission_rate, + ) + venting_emitter_results[emission_name] = emission_result + return venting_emitter_results + + def get_oil_rates( + self, + expression_evaluator: ExpressionEvaluator, + regularity: TimeSeriesFloat, + ) -> TimeSeriesStreamDayRate: + oil_rates = self._expression_evaluator.evaluate( + convert_expression(self._yaml_venting_emitter.volume.rate.value) + ) + + if self._yaml_venting_emitter.volume.rate.type == RateType.CALENDAR_DAY: + oil_rates = Rates.to_stream_day( + calendar_day_rates=np.asarray(oil_rates), + regularity=regularity.values, + ).tolist() + + unit = self._yaml_venting_emitter.volume.rate.unit.to_unit() + oil_rates = unit.to(Unit.STANDARD_CUBIC_METER_PER_DAY)(oil_rates) + + return TimeSeriesStreamDayRate( + timesteps=expression_evaluator.get_time_vector(), + values=oil_rates, + unit=Unit.STANDARD_CUBIC_METER_PER_DAY, + ) + + def get_ecalc_model_result(self) -> Optional[EcalcModelResult]: + return None diff --git a/src/libecalc/presentation/yaml/domain/reference_service.py b/src/libecalc/presentation/yaml/domain/reference_service.py new file mode 100644 index 0000000000..f52e6e3ef2 --- /dev/null +++ b/src/libecalc/presentation/yaml/domain/reference_service.py @@ -0,0 +1,24 @@ +from typing import Iterable, Protocol + +from libecalc.dto import CompressorModel, FuelType, GeneratorSetSampled, PumpModel, TabulatedData + + +class InvalidReferenceException(Exception): + def __init__(self, reference_type: str, reference: str, available_references: Iterable[str] = None): + if available_references is not None: + available_message = f"Available references: {', '.join(available_references)}" + else: + available_message = "" + super().__init__(f"Invalid {reference_type} reference '{reference}'. {available_message}") + + +class ReferenceService(Protocol): + def get_fuel_reference(self, reference: str) -> FuelType: ... + + def get_generator_set_model(self, reference: str) -> GeneratorSetSampled: ... + + def get_compressor_model(self, reference: str) -> CompressorModel: ... + + def get_pump_model(self, reference: str) -> PumpModel: ... + + def get_tabulated_model(self, reference: str) -> TabulatedData: ... diff --git a/src/libecalc/presentation/yaml/mappers/component_mapper.py b/src/libecalc/presentation/yaml/mappers/component_mapper.py index fe0e36cae1..e3ad5fc08e 100644 --- a/src/libecalc/presentation/yaml/mappers/component_mapper.py +++ b/src/libecalc/presentation/yaml/mappers/component_mapper.py @@ -7,22 +7,20 @@ from libecalc.common.consumer_type import ConsumerType from libecalc.common.consumption_type import ConsumptionType from libecalc.common.energy_model_type import EnergyModelType -from libecalc.common.errors.exceptions import InvalidReferenceException from libecalc.common.logger import logger from libecalc.common.time_utils import Period, define_time_model_for_period from libecalc.dto import ConsumerFunction, FuelType from libecalc.dto.components import Asset, Consumer, ElectricityConsumer, FuelConsumer, GeneratorSet, Installation from libecalc.dto.utils.validators import convert_expression from libecalc.expression import Expression +from libecalc.presentation.yaml.domain.reference_service import InvalidReferenceException, ReferenceService from libecalc.presentation.yaml.mappers.consumer_function_mapper import ( ConsumerFunctionMapper, ) -from libecalc.presentation.yaml.mappers.utils import resolve_reference from libecalc.presentation.yaml.validation_errors import ( DataValidationError, DtoValidationError, ) -from libecalc.presentation.yaml.yaml_entities import References from libecalc.presentation.yaml.yaml_models.yaml_model import YamlValidator from libecalc.presentation.yaml.yaml_types.components.legacy.yaml_electricity_consumer import YamlElectricityConsumer from libecalc.presentation.yaml.yaml_types.components.legacy.yaml_fuel_consumer import YamlFuelConsumer @@ -65,7 +63,7 @@ def _get_component_type(energy_usage_models: Dict[datetime, ConsumerFunction]) - def _resolve_fuel( consumer_fuel: Union[Optional[str], Dict], default_fuel: Optional[str], - references: References, + references: ReferenceService, target_period: Period, ) -> Optional[Dict[datetime, FuelType]]: fuel = consumer_fuel or default_fuel # Use parent fuel only if not specified on this consumer @@ -77,10 +75,7 @@ def _resolve_fuel( temporal_fuel_model = {} for start_time, fuel in time_adjusted_fuel.items(): - resolved_fuel = resolve_reference( - fuel, - references=references.fuel_types, - ) + resolved_fuel = references.get_fuel_reference(fuel) temporal_fuel_model[start_time] = resolved_fuel @@ -88,7 +83,7 @@ def _resolve_fuel( class ConsumerMapper: - def __init__(self, references: References, target_period: Period): + def __init__(self, references: ReferenceService, target_period: Period): self.__references = references self._target_period = target_period self.__energy_usage_model_mapper = ConsumerFunctionMapper(references=references, target_period=target_period) @@ -116,7 +111,7 @@ def from_yaml_to_dto( except InvalidReferenceException as e: raise DataValidationError( data=data.model_dump(), - message=f"Fuel '{consumer_fuel or default_fuel}' does not exist", + message=str(e), error_key="fuel", ) from e @@ -132,13 +127,8 @@ def from_yaml_to_dto( except ValidationError as e: raise DtoValidationError(data=data.model_dump(), validation_error=e) from e - energy_usage_model = resolve_reference( - data.energy_usage_model, - references=self.__references.models, - ) # TODO: This is never a reference? So resolve_reference always return the same value, remove - try: - energy_usage_model = self.__energy_usage_model_mapper.from_yaml_to_dto(energy_usage_model) + energy_usage_model = self.__energy_usage_model_mapper.from_yaml_to_dto(data.energy_usage_model) except ValidationError as e: raise DtoValidationError(data=data.model_dump(), validation_error=e) from e @@ -174,7 +164,7 @@ def from_yaml_to_dto( class GeneratorSetMapper: - def __init__(self, references: References, target_period: Period): + def __init__(self, references: ReferenceService, target_period: Period): self.__references = references self._target_period = target_period self.__consumer_mapper = ConsumerMapper(references=references, target_period=target_period) @@ -197,11 +187,8 @@ def from_yaml_to_dto( data.electricity2fuel, target_period=self._target_period ) generator_set_model = { - start_time: resolve_reference( - model_timestep, - references=self.__references.models, - ) - for start_time, model_timestep in generator_set_model_data.items() + start_time: self.__references.get_generator_set_model(model_reference) + for start_time, model_reference in generator_set_model_data.items() } # When consumers was created directly in the return dto.GeneratorSet - function, @@ -237,7 +224,7 @@ def from_yaml_to_dto( class InstallationMapper: - def __init__(self, references: References, target_period: Period): + def __init__(self, references: ReferenceService, target_period: Period): self.__references = references self._target_period = target_period self.__generator_set_mapper = GeneratorSetMapper(references=references, target_period=target_period) @@ -290,7 +277,7 @@ def from_yaml_to_dto(self, data: YamlInstallation) -> Installation: class EcalcModelMapper: def __init__( self, - references: References, + references: ReferenceService, target_period: Period, ): self.__references = references diff --git a/src/libecalc/presentation/yaml/mappers/consumer_function_mapper.py b/src/libecalc/presentation/yaml/mappers/consumer_function_mapper.py index 7ed890e3e1..5330e878a2 100644 --- a/src/libecalc/presentation/yaml/mappers/consumer_function_mapper.py +++ b/src/libecalc/presentation/yaml/mappers/consumer_function_mapper.py @@ -23,10 +23,7 @@ VariableSpeedCompressorTrainMultipleStreamsAndPressures, ) from libecalc.expression import Expression -from libecalc.presentation.yaml.mappers.utils import ( - resolve_reference, -) -from libecalc.presentation.yaml.yaml_entities import References +from libecalc.presentation.yaml.domain.reference_service import ReferenceService from libecalc.presentation.yaml.yaml_keywords import EcalcYamlKeywords from libecalc.presentation.yaml.yaml_types.components.legacy.energy_usage_model import ( YamlElectricityEnergyUsageModel, @@ -94,15 +91,12 @@ def _get_compressor_train_energy_usage_type( def _compressor_system_mapper( - energy_usage_model: YamlEnergyUsageModelCompressorSystem, references: References = None + energy_usage_model: YamlEnergyUsageModelCompressorSystem, references: ReferenceService ) -> CompressorSystemConsumerFunction: compressors = [] compressor_power_usage_type = set() for compressor in energy_usage_model.compressors: - compressor_train = resolve_reference( - value=compressor.compressor_model, - references=references.models, - ) + compressor_train = references.get_compressor_model(compressor.compressor_model) compressors.append( CompressorSystemCompressor( @@ -145,7 +139,7 @@ def _compressor_system_mapper( def _pump_system_mapper( - energy_usage_model: YamlEnergyUsageModelPumpSystem, references: References = None + energy_usage_model: YamlEnergyUsageModelPumpSystem, references: ReferenceService ) -> PumpSystemConsumerFunction: """Remove references from pump system and map yaml to DTO :param energy_usage_model: dict representing PumpSystem @@ -153,10 +147,7 @@ def _pump_system_mapper( """ pumps = [] for pump in energy_usage_model.pumps: - pump_model = resolve_reference( - pump.chart, - references=references.models, - ) + pump_model = references.get_pump_model(pump.chart) pumps.append(PumpSystemPump(name=pump.name, pump_model=pump_model)) return PumpSystemConsumerFunction( @@ -182,7 +173,7 @@ def _pump_system_mapper( def _direct_mapper( - energy_usage_model: YamlEnergyUsageModelDirect, references: References = None + energy_usage_model: YamlEnergyUsageModelDirect, references: ReferenceService ) -> DirectConsumerFunction: """Change type to match DTOs, then pass the dict on to DTO to automatically create the correct DTO. :param energy_usage_model: @@ -200,12 +191,9 @@ def _direct_mapper( def _tabulated_mapper( - energy_usage_model: YamlEnergyUsageModelTabulated, references: References = None + energy_usage_model: YamlEnergyUsageModelTabulated, references: ReferenceService ) -> TabulatedConsumerFunction: - energy_model = resolve_reference( - energy_usage_model.energy_function, - references.models, - ) + energy_model = references.get_tabulated_model(energy_usage_model.energy_function) return TabulatedConsumerFunction( energy_usage_type=EnergyUsageType.POWER if EnergyUsageType.POWER.value in energy_model.headers @@ -223,11 +211,8 @@ def _tabulated_mapper( ) -def _pump_mapper(energy_usage_model: YamlEnergyUsageModelPump, references: References = None) -> PumpConsumerFunction: - energy_model = resolve_reference( - energy_usage_model.energy_function, - references=references.models, - ) +def _pump_mapper(energy_usage_model: YamlEnergyUsageModelPump, references: ReferenceService) -> PumpConsumerFunction: + energy_model = references.get_pump_model(energy_usage_model.energy_function) return PumpConsumerFunction( power_loss_factor=energy_usage_model.power_loss_factor, condition=_map_condition(energy_usage_model), @@ -240,12 +225,9 @@ def _pump_mapper(energy_usage_model: YamlEnergyUsageModelPump, references: Refer def _variable_speed_compressor_train_multiple_streams_and_pressures_mapper( - energy_usage_model: YamlEnergyUsageModelCompressorTrainMultipleStreams, references: References = None + energy_usage_model: YamlEnergyUsageModelCompressorTrainMultipleStreams, references: ReferenceService ) -> CompressorConsumerFunction: - compressor_train_model = resolve_reference( - energy_usage_model.compressor_train_model, - references=references.models, - ) + compressor_train_model = references.get_compressor_model(energy_usage_model.compressor_train_model) rates_per_stream = [ Expression.setup_from_expression(value=rate_expression) for rate_expression in energy_usage_model.rate_per_stream @@ -293,13 +275,9 @@ def _variable_speed_compressor_train_multiple_streams_and_pressures_mapper( def _compressor_mapper( - energy_usage_model: YamlEnergyUsageModelCompressor, references: References = None + energy_usage_model: YamlEnergyUsageModelCompressor, references: ReferenceService ) -> CompressorConsumerFunction: - energy_model = resolve_reference( - energy_usage_model.energy_function, - references=references.models, - ) - + energy_model = references.get_compressor_model(energy_usage_model.energy_function) compressor_train_energy_usage_type = _get_compressor_train_energy_usage_type(compressor_train=energy_model) return CompressorConsumerFunction( @@ -325,14 +303,14 @@ def _compressor_mapper( class ConsumerFunctionMapper: - def __init__(self, references: References, target_period: Period): + def __init__(self, references: ReferenceService, target_period: Period): self.__references = references self._target_period = target_period @staticmethod def create_model( model: Union[YamlFuelEnergyUsageModel, YamlElectricityEnergyUsageModel], - references: References = None, + references: ReferenceService, ): model_creator = _consumer_function_mapper.get(model.type) if model_creator is None: diff --git a/src/libecalc/presentation/yaml/mappers/create_references.py b/src/libecalc/presentation/yaml/mappers/create_references.py index d5c450273e..442b8544db 100644 --- a/src/libecalc/presentation/yaml/mappers/create_references.py +++ b/src/libecalc/presentation/yaml/mappers/create_references.py @@ -4,6 +4,7 @@ from libecalc.common.logger import logger from libecalc.common.string.string_utils import get_duplicates from libecalc.dto import EnergyModel +from libecalc.presentation.yaml.domain.reference_service import ReferenceService from libecalc.presentation.yaml.mappers.facility_input import FacilityInputMapper from libecalc.presentation.yaml.mappers.fuel_and_emission_mapper import FuelMapper from libecalc.presentation.yaml.mappers.model import ModelMapper @@ -14,7 +15,7 @@ from libecalc.presentation.yaml.yaml_types.models import YamlConsumerModel -def create_references(configuration: YamlValidator, resources: Resources) -> References: +def create_references(configuration: YamlValidator, resources: Resources) -> ReferenceService: """Create references-lookup used throughout the yaml. :param resources: list of resources containing data for the FILE reference in facility input diff --git a/src/libecalc/presentation/yaml/mappers/utils.py b/src/libecalc/presentation/yaml/mappers/utils.py index efdb65dfc2..440db7718e 100644 --- a/src/libecalc/presentation/yaml/mappers/utils.py +++ b/src/libecalc/presentation/yaml/mappers/utils.py @@ -3,7 +3,7 @@ import pandas as pd -from libecalc.common.errors.exceptions import HeaderNotFoundException, InvalidReferenceException +from libecalc.common.errors.exceptions import HeaderNotFoundException from libecalc.common.logger import logger from libecalc.common.units import Unit from libecalc.dto.types import ( @@ -12,6 +12,7 @@ ChartPolytropicHeadUnit, ChartRateUnit, ) +from libecalc.presentation.yaml.domain.reference_service import InvalidReferenceException from libecalc.presentation.yaml.resource import Resource from libecalc.presentation.yaml.validation_errors import ( ResourceValidationError, diff --git a/src/libecalc/presentation/yaml/model.py b/src/libecalc/presentation/yaml/model.py index 6eb1eec3b3..f3d7310d8a 100644 --- a/src/libecalc/presentation/yaml/model.py +++ b/src/libecalc/presentation/yaml/model.py @@ -4,16 +4,19 @@ from typing_extensions import Self, deprecated -from libecalc.common.time_utils import Frequency +from libecalc.common.time_utils import Frequency, Period from libecalc.common.variables import VariablesMap from libecalc.dto import ResultOptions from libecalc.dto.component_graph import ComponentGraph from libecalc.presentation.yaml.configuration_service import ConfigurationService +from libecalc.presentation.yaml.domain.components.asset_component import AssetComponent +from libecalc.presentation.yaml.domain.reference_service import ReferenceService from libecalc.presentation.yaml.domain.time_series_collections import TimeSeriesCollections +from libecalc.presentation.yaml.mappers.component_mapper import EcalcModelMapper +from libecalc.presentation.yaml.mappers.create_references import create_references from libecalc.presentation.yaml.mappers.variables_mapper import map_yaml_to_variables from libecalc.presentation.yaml.mappers.variables_mapper.get_global_time_vector import get_global_time_vector from libecalc.presentation.yaml.model_validation_exception import ModelValidationException -from libecalc.presentation.yaml.parse_input import map_yaml_to_dto from libecalc.presentation.yaml.resource_service import ResourceService from libecalc.presentation.yaml.validation_errors import DtoValidationError from libecalc.presentation.yaml.yaml_models.yaml_model import YamlValidator @@ -24,6 +27,8 @@ YamlModelValidationContextNames, ) +DEFAULT_START_TIME = datetime(1900, 1, 1) + class YamlModel: """ @@ -52,13 +57,27 @@ def __init__( self._is_validated = False + def _get_reference_service(self) -> ReferenceService: + return create_references(self._configuration, self.resources) + @cached_property @deprecated( "Avoid using the dto objects directly, we want to remove them. get_graph() might be useful instead, although the nodes will change." ) def dto(self): self.validate_for_run() - return map_yaml_to_dto(configuration=self._configuration, resources=self.resources) + model_mapper = EcalcModelMapper( + references=self._get_reference_service(), + target_period=self.period, + ) + return model_mapper.from_yaml_to_dto(configuration=self._configuration) + + @property + def period(self) -> Period: + return Period( + start=self.start or DEFAULT_START_TIME, + end=self.end or datetime.max, + ) @property def start(self) -> Optional[datetime]: @@ -74,8 +93,8 @@ def _get_time_series_collections(self) -> TimeSeriesCollections: def _get_time_vector(self): return get_global_time_vector( time_series_time_vector=self._get_time_series_collections().get_time_vector(), - start=self.start, - end=self.end, + start=self._configuration.start, + end=self._configuration.end, frequency=self._output_frequency, additional_dates=self._configuration.dates, ) @@ -97,7 +116,13 @@ def result_options(self) -> ResultOptions: ) def get_graph(self) -> ComponentGraph: - return self.dto.get_graph() + asset = AssetComponent( + yaml_asset=self._configuration, + reference_service=self._get_reference_service(), + target_period=self.period, + expression_evaluator=self.variables, + ) + return asset.get_graph() def _get_token_references(self, yaml_model: YamlValidator) -> List[str]: token_references = self._get_time_series_collections().get_time_series_references() diff --git a/src/libecalc/presentation/yaml/parse_input.py b/src/libecalc/presentation/yaml/parse_input.py deleted file mode 100644 index b7dfbdff00..0000000000 --- a/src/libecalc/presentation/yaml/parse_input.py +++ /dev/null @@ -1,24 +0,0 @@ -from datetime import datetime - -from libecalc.common.time_utils import Period -from libecalc.dto import Asset -from libecalc.presentation.yaml.mappers.component_mapper import EcalcModelMapper -from libecalc.presentation.yaml.mappers.create_references import create_references -from libecalc.presentation.yaml.resource import Resources -from libecalc.presentation.yaml.yaml_models.yaml_model import YamlValidator - -DEFAULT_START_TIME = datetime(1900, 1, 1) - - -def map_yaml_to_dto(configuration: YamlValidator, resources: Resources) -> Asset: - # TODO: Replace configuration type with YamlValidator - references = create_references(configuration, resources) - target_period = Period( - start=configuration.start or DEFAULT_START_TIME, - end=configuration.end or datetime.max, - ) - model_mapper = EcalcModelMapper( - references=references, - target_period=target_period, - ) - return model_mapper.from_yaml_to_dto(configuration=configuration) diff --git a/src/libecalc/presentation/yaml/yaml_entities.py b/src/libecalc/presentation/yaml/yaml_entities.py index 68bd461f14..0a61dbeedf 100644 --- a/src/libecalc/presentation/yaml/yaml_entities.py +++ b/src/libecalc/presentation/yaml/yaml_entities.py @@ -1,9 +1,10 @@ from dataclasses import dataclass from enum import Enum -from typing import Dict, List, TextIO, Union +from typing import Dict, List, TextIO, TypeVar, Union, get_args from libecalc.common.errors.exceptions import ColumnNotFoundException, HeaderNotFoundException -from libecalc.dto import EnergyModel, FuelType +from libecalc.dto import CompressorModel, EnergyModel, FuelType, GeneratorSetSampled, PumpModel, TabulatedData +from libecalc.presentation.yaml.domain.reference_service import InvalidReferenceException, ReferenceService from libecalc.presentation.yaml.resource import Resource @@ -30,11 +31,50 @@ def get_column(self, header: str) -> List[Union[float, int, str]]: raise ColumnNotFoundException(header=header) from e +TModelType = TypeVar("TModelType", bound=Union[GeneratorSetSampled, CompressorModel, PumpModel, TabulatedData]) + + @dataclass -class References: +class References(ReferenceService): models: Dict[str, EnergyModel] = None fuel_types: Dict[str, FuelType] = None + def get_fuel_reference(self, reference: str) -> FuelType: + try: + return self.fuel_types[reference] + except KeyError as e: + raise InvalidReferenceException("fuel", reference, self.fuel_types.keys()) from e + + def _get_model_reference(self, reference: str, reference_type_name: str) -> EnergyModel: + try: + return self.models[reference] + except KeyError as e: + raise InvalidReferenceException(reference_type_name, reference, self.models.keys()) from e + + def get_generator_set_model(self, reference: str) -> GeneratorSetSampled: + model = self._get_model_reference(reference, "generator set model") + if not isinstance(model, GeneratorSetSampled): + raise InvalidReferenceException("generator set model", reference) + return model + + def get_compressor_model(self, reference: str) -> CompressorModel: + model = self._get_model_reference(reference, "compressor model") + if not isinstance(model, get_args(CompressorModel)): + raise InvalidReferenceException("compressor model", reference) + return model # noqa + + def get_pump_model(self, reference: str) -> PumpModel: + model = self._get_model_reference(reference, "compressor model") + if not isinstance(model, PumpModel): + raise InvalidReferenceException("pump model", reference) + return model + + def get_tabulated_model(self, reference: str) -> TabulatedData: + model = self._get_model_reference(reference, "tabulated") + if not isinstance(model, TabulatedData): + raise InvalidReferenceException("tabulated", reference) + return model + class YamlTimeseriesType(str, Enum): MISCELLANEOUS = "MISCELLANEOUS" diff --git a/src/libecalc/presentation/yaml/yaml_types/components/system/yaml_consumer_system.py b/src/libecalc/presentation/yaml/yaml_types/components/system/yaml_consumer_system.py index d7ce28c627..bd8c438b51 100644 --- a/src/libecalc/presentation/yaml/yaml_types/components/system/yaml_consumer_system.py +++ b/src/libecalc/presentation/yaml/yaml_types/components/system/yaml_consumer_system.py @@ -10,7 +10,7 @@ from libecalc.dto import FuelType from libecalc.dto.components import ConsumerSystem, Crossover, SystemComponentConditions from libecalc.expression import Expression -from libecalc.presentation.yaml.yaml_entities import References +from libecalc.presentation.yaml.domain.reference_service import ReferenceService from libecalc.presentation.yaml.yaml_types.components.system.yaml_system_component_conditions import ( YamlSystemComponentConditions, ) @@ -72,7 +72,7 @@ def to_dto( self, regularity: Dict[datetime, Expression], consumes: ConsumptionType, - references: References, + references: ReferenceService, target_period: Period, fuel: Optional[Dict[datetime, FuelType]] = None, ) -> ConsumerSystem: diff --git a/src/libecalc/presentation/yaml/yaml_types/components/train/yaml_train.py b/src/libecalc/presentation/yaml/yaml_types/components/train/yaml_train.py index 6cc5aac585..aaa0188f35 100644 --- a/src/libecalc/presentation/yaml/yaml_types/components/train/yaml_train.py +++ b/src/libecalc/presentation/yaml/yaml_types/components/train/yaml_train.py @@ -9,7 +9,7 @@ from libecalc.common.time_utils import Period from libecalc.dto.components import Stream, TrainComponent from libecalc.expression import Expression -from libecalc.presentation.yaml.yaml_entities import References +from libecalc.presentation.yaml.domain.reference_service import ReferenceService from libecalc.presentation.yaml.yaml_types.components.yaml_base import YamlConsumerBase from libecalc.presentation.yaml.yaml_types.components.yaml_compressor import ( YamlCompressor, @@ -34,7 +34,7 @@ def to_dto( consumes: ConsumptionType, regularity: Dict[datetime, Expression], target_period: Period, - references: References, + references: ReferenceService, category: str, fuel: Optional[Dict[datetime, libecalc.dto.fuel_type.FuelType]], ): diff --git a/src/libecalc/presentation/yaml/yaml_types/components/yaml_compressor.py b/src/libecalc/presentation/yaml/yaml_types/components/yaml_compressor.py index 679859bef3..dd3b6425dc 100644 --- a/src/libecalc/presentation/yaml/yaml_types/components/yaml_compressor.py +++ b/src/libecalc/presentation/yaml/yaml_types/components/yaml_compressor.py @@ -9,8 +9,7 @@ from libecalc.dto import FuelType from libecalc.dto.components import CompressorComponent from libecalc.expression import Expression -from libecalc.presentation.yaml.mappers.utils import resolve_reference -from libecalc.presentation.yaml.yaml_entities import References +from libecalc.presentation.yaml.domain.reference_service import ReferenceService from libecalc.presentation.yaml.yaml_types.components.yaml_base import ( YamlConsumerBase, ) @@ -40,7 +39,7 @@ def to_dto( consumes: ConsumptionType, regularity: Dict[datetime, Expression], target_period: Period, - references: References, + references: ReferenceService, category: str, fuel: Optional[Dict[datetime, FuelType]], ): @@ -51,10 +50,7 @@ def to_dto( user_defined_category=define_time_model_for_period(self.category or category, target_period=target_period), fuel=fuel, energy_usage_model={ - timestep: resolve_reference( - value=reference, - references=references.models, - ) + timestep: references.get_compressor_model(reference) for timestep, reference in define_time_model_for_period( self.energy_usage_model, target_period=target_period ).items() diff --git a/src/libecalc/presentation/yaml/yaml_types/components/yaml_installation.py b/src/libecalc/presentation/yaml/yaml_types/components/yaml_installation.py index 5989039197..230b2914cb 100644 --- a/src/libecalc/presentation/yaml/yaml_types/components/yaml_installation.py +++ b/src/libecalc/presentation/yaml/yaml_types/components/yaml_installation.py @@ -39,7 +39,7 @@ class YamlInstallation(YamlBase): ) category: InstallationUserDefinedCategoryType = CategoryField(None) hydrocarbon_export: YamlTemporalModel[YamlExpressionType] = Field( - None, + 0, title="HCEXPORT", description="Defines the export of hydrocarbons as number of oil equivalents in Sm3.\n\n$ECALC_DOCS_KEYWORDS_URL/HCEXPORT", alias="HCEXPORT", @@ -50,7 +50,7 @@ class YamlInstallation(YamlBase): description="Main fuel type for installation." "\n\n$ECALC_DOCS_KEYWORDS_URL/FUEL", ) regularity: YamlTemporalModel[YamlExpressionType] = Field( - None, + 1, title="REGULARITY", description="Regularity of the installation can be specified by a single number or as an expression. USE WITH CARE.\n\n$ECALC_DOCS_KEYWORDS_URL/REGULARITY", ) @@ -83,12 +83,10 @@ class YamlInstallation(YamlBase): @model_validator(mode="after") def check_some_consumer_or_emitter(self): - try: - if self.fuel_consumers or self.venting_emitters or self.generator_sets: - return self - except AttributeError: + if self.fuel_consumers or self.venting_emitters or self.generator_sets: + return self + else: raise ValueError( f"Keywords are missing:\n It is required to specify at least one of the keywords " f"{EcalcYamlKeywords.fuel_consumers}, {EcalcYamlKeywords.generator_sets} or {EcalcYamlKeywords.installation_venting_emitters} in the model.", ) from None - return self diff --git a/src/libecalc/presentation/yaml/yaml_types/components/yaml_pump.py b/src/libecalc/presentation/yaml/yaml_types/components/yaml_pump.py index 1b45b24ac2..713ce6c5ce 100644 --- a/src/libecalc/presentation/yaml/yaml_types/components/yaml_pump.py +++ b/src/libecalc/presentation/yaml/yaml_types/components/yaml_pump.py @@ -9,8 +9,7 @@ from libecalc.dto import FuelType from libecalc.dto.components import PumpComponent from libecalc.expression import Expression -from libecalc.presentation.yaml.mappers.utils import resolve_reference -from libecalc.presentation.yaml.yaml_entities import References +from libecalc.presentation.yaml.domain.reference_service import ReferenceService from libecalc.presentation.yaml.yaml_types.components.yaml_base import ( YamlConsumerBase, ) @@ -37,7 +36,7 @@ def to_dto( consumes: ConsumptionType, regularity: Dict[datetime, Expression], target_period: Period, - references: References, + references: ReferenceService, category: str, fuel: Optional[Dict[datetime, FuelType]], ): @@ -48,10 +47,7 @@ def to_dto( user_defined_category=define_time_model_for_period(self.category or category, target_period=target_period), fuel=fuel, energy_usage_model={ - timestep: resolve_reference( - value=reference, - references=references.models, - ) + timestep: references.get_pump_model(reference) for timestep, reference in define_time_model_for_period( self.energy_usage_model, target_period=target_period ).items() diff --git a/src/libecalc/presentation/yaml/yaml_types/yaml_temporal_model.py b/src/libecalc/presentation/yaml/yaml_types/yaml_temporal_model.py index 9b642e2fd2..387af166da 100644 --- a/src/libecalc/presentation/yaml/yaml_types/yaml_temporal_model.py +++ b/src/libecalc/presentation/yaml/yaml_types/yaml_temporal_model.py @@ -1,10 +1,11 @@ from typing import Any, Dict, TypeVar, Union -from pydantic import Discriminator, Tag +from pydantic import AfterValidator, Discriminator, Tag from typing_extensions import Annotated, Literal from libecalc.common.errors.exceptions import InvalidDateException from libecalc.common.time_utils import is_temporal_model +from libecalc.dto.utils.validators import validate_temporal_model from libecalc.presentation.yaml.yaml_types.yaml_default_datetime import ( YamlDefaultDatetime, ) @@ -38,7 +39,7 @@ def discriminate_temporal_model(v: Any) -> Literal["single", "temporal"]: Union[ Annotated[TModel, Tag("single")], Annotated[ - Dict[YamlDefaultDatetime, TModel], + Annotated[Dict[YamlDefaultDatetime, TModel], AfterValidator(validate_temporal_model)], Tag("temporal"), ], ], diff --git a/src/tests/ecalc_cli/snapshots/test_app/test_csv_default/test.csv b/src/tests/ecalc_cli/snapshots/test_app/test_csv_default/test.csv index 6b49ebc8b9..0656fccf29 100644 --- a/src/tests/ecalc_cli/snapshots/test_app/test_csv_default/test.csv +++ b/src/tests/ecalc_cli/snapshots/test_app/test_csv_default/test.csv @@ -1,13 +1,13 @@ timesteps,model.is_valid[N/A],model.energy_usage[Sm3/cd],model.energy_usage_cumulative[Sm3 (cd)],model.power[MW (sd)],model.power_cumulative[GWh (cd)],model.co2.rate[t/cd],model.co2.cumulative[t (cd)],model.hydrocarbon_export_rate[Sm3/cd],model.co2.intensity_sm3[kg/Sm3],model.co2.intensity_boe[kg/BOE],model.co2.intensity_yearly_sm3[kg/Sm3],model.co2.intensity_yearly_boe[kg/BOE],model.power_electrical[MW (sd)],model.power_electrical_cumulative[GWh (cd)],model.power_mechanical[MW (sd)],model.power_mechanical_cumulative[GWh (cd)],Installation A.is_valid[N/A],Installation A.energy_usage[Sm3/cd],Installation A.energy_usage_cumulative[Sm3 (cd)],Installation A.power[MW (sd)],Installation A.power_cumulative[GWh (cd)],Installation A.co2.rate[t/cd],Installation A.co2.cumulative[t (cd)],Installation A.hydrocarbon_export_rate[Sm3/cd],Installation A.co2.intensity_sm3[kg/Sm3],Installation A.co2.intensity_boe[kg/BOE],Installation A.co2.intensity_yearly_sm3[kg/Sm3],Installation A.co2.intensity_yearly_boe[kg/BOE],Installation A.power_electrical[MW (sd)],Installation A.power_electrical_cumulative[GWh (cd)],Installation A.power_mechanical[MW (sd)],Installation A.power_mechanical_cumulative[GWh (cd)],Installation A.regularity[N/A],Generator set A.is_valid[N/A],Generator set A.energy_usage[Sm3/cd],Generator set A.energy_usage_cumulative[Sm3 (cd)],Generator set A.power[MW (sd)],Generator set A.power_cumulative[GWh (cd)],Generator set A.co2.rate[t/cd],Generator set A.co2.cumulative[t (cd)],Generator set A.power_capacity_margin[MW (sd)],Gas export compressor.is_valid[N/A],Gas export compressor.energy_usage[Sm3/cd],Gas export compressor.energy_usage_cumulative[Sm3 (cd)],Gas export compressor.co2.rate[t/cd],Gas export compressor.co2.cumulative[t (cd)],Gas export compressor.recirculation_loss[MW (sd)],Gas export compressor.rate_exceeds_maximum[N/A],Gas injection compressor.is_valid[N/A],Gas injection compressor.energy_usage[MW (sd)],Gas injection compressor.energy_usage_cumulative[MWd (cd)],Gas injection compressor.power[MW (sd)],Gas injection compressor.power_cumulative[GWh (cd)],Gas injection compressor.recirculation_loss[MW (sd)],Gas injection compressor.rate_exceeds_maximum[N/A],Produced water reinjection pump.is_valid[N/A],Produced water reinjection pump.energy_usage[MW (sd)],Produced water reinjection pump.energy_usage_cumulative[MWd (cd)],Produced water reinjection pump.power[MW (sd)],Produced water reinjection pump.power_cumulative[GWh (cd)],Produced water reinjection pump.inlet_liquid_rate_m3_per_day[Sm3/sd],Produced water reinjection pump.inlet_pressure_bar[bara],Produced water reinjection pump.outlet_pressure_bar[bara],Produced water reinjection pump.operational_head[J/kg],Base production load.is_valid[N/A],Base production load.energy_usage[MW (sd)],Base production load.energy_usage_cumulative[MWd (cd)],Base production load.power[MW (sd)],Base production load.power_cumulative[GWh (cd)],Flare.is_valid[N/A],Flare.energy_usage[Sm3/cd],Flare.energy_usage_cumulative[Sm3 (cd)],Flare.co2.rate[t/cd],Flare.co2.cumulative[t (cd)],Sea water injection pump.is_valid[N/A],Sea water injection pump.energy_usage[MW (sd)],Sea water injection pump.energy_usage_cumulative[MWd (cd)],Sea water injection pump.power[MW (sd)],Sea water injection pump.power_cumulative[GWh (cd)] 2020-01-01 00:00:00,1, 310830.00000, 0.00000, 27.71452, 0.00000, 680.71770, 0.00000, 12500.00000,nan,nan,54.45742,8.657777, 27.71452, 0.00000, 0.00000, 0.00000,1, 310830.00000, 0.00000, 27.71452, 0.00000, 680.71770, 0.00000, 12500.00000,nan,nan,54.45742,8.657777, 27.71452, 0.00000, 0.00000, 0.00000, 1.00000,1, 173830.00000, 0.00000, 27.71452, 0.00000, 380.68770, 0.00000, 72.28548,1, 130000.00000, 0.00000, 284.70000, 0.00000, 0.00000,0,1, 4.89000, 0.00000, 4.89000, 0.00000, 0.00000,0,1, 5.02452, 0.00000, 5.02452, 0.00000, 17000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 0.00000, 11.80000, 0.00000,1, 7000.00000, 0.00000, 15.33000, 0.00000,1, 6.00000, 0.00000, 6.00000, 0.00000 -2021-01-01 00:00:00,1, 311343.90000, 113763780.00000, 27.61307, 243.44430, 681.84320, 249142.70000, 11600.00000,54.45742,8.657777,58.77959,9.344926, 27.61307, 243.44430, 0.00000, 0.00000,1, 311343.90000, 113763780.00000, 27.61307, 243.44430, 681.84320, 249142.70000, 11600.00000,54.45742,8.657777,58.77959,9.344926, 27.61307, 243.44430, 0.00000, 0.00000, 1.00000,1, 173201.00000, 63621780.00000, 27.61307, 243.44430, 379.31020, 139331.70000, 72.38693,1, 131142.90000, 47580000.00000, 287.20300, 104200.20000, 0.00000,0,1, 5.01000, 1789.74000, 5.01000, 42.95376, 0.00000,0,1, 5.05307, 1838.97300, 5.05307, 44.13536, 17200.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 4318.80000, 11.80000, 103.65120,1, 7000.00000, 2562000.00000, 15.33000, 5610.78000,1, 5.75000, 2196.00000, 5.75000, 52.70400 -2022-01-01 00:00:00,1, 309378.10000, 227404304.00000, 27.11168, 485.33480, 677.53810, 498015.40000, 10700.00000,56.53484,8.988052,63.32132,10.06698, 27.11168, 485.33480, 0.00000, 0.00000,1, 309378.10000, 227404304.00000, 27.11168, 485.33480, 677.53810, 498015.40000, 10700.00000,56.53484,8.988052,63.32132,10.06698, 27.11168, 485.33480, 0.00000, 0.00000, 1.00000,1, 170092.40000, 126840145.00000, 27.11168, 485.33480, 372.50240, 277779.90000, 72.88832,1, 132285.70000, 95447158.00000, 289.70570, 209029.30000, 0.00000,0,1, 5.13000, 3618.39000, 5.13000, 86.84136, 0.00000,0,1, 4.68168, 3683.34500, 4.68168, 88.40027, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 8625.80000, 11.80000, 207.01920,1, 7000.00000, 5117000.00000, 15.33000, 11206.23000,1, 5.50000, 4294.75000, 5.50000, 103.07400 -2023-01-01 00:00:00,1, 317428.00000, 340327310.00000, 28.22570, 722.83320, 695.16730, 745316.90000, 9800.00000,58.61944,9.319466,70.93544,11.27749, 28.22570, 722.83320, 0.00000, 0.00000,1, 317428.00000, 340327310.00000, 28.22570, 722.83320, 695.16730, 745316.90000, 9800.00000,58.61944,9.319466,70.93544,11.27749, 28.22570, 722.83320, 0.00000, 0.00000, 1.00000,1, 176999.40000, 188923871.00000, 28.22570, 722.83320, 387.62870, 413743.30000, 71.77430,1, 133428.60000, 143731439.00000, 292.20860, 314771.90000, 0.00000,0,1, 5.56000, 5490.84000, 5.56000, 131.78020, 0.00000,0,1, 4.86570, 5392.15600, 4.86570, 129.41170, 16000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 12932.80000, 11.80000, 310.38720,1, 7000.00000, 7672000.00000, 15.33000, 16801.68000,1, 6.00000, 6302.25000, 6.00000, 151.25400 -2024-01-01 00:00:00,1, 340633.50000, 456188530.00000, 31.78422, 970.09030, 745.98740, 999052.90000, 9900.00000,61.32357,9.749375,75.37705,11.98363, 31.78422, 970.09030, 0.00000, 0.00000,1, 340633.50000, 456188530.00000, 31.78422, 970.09030, 745.98740, 999052.90000, 9900.00000,61.32357,9.749375,75.37705,11.98363, 31.78422, 970.09030, 0.00000, 0.00000, 1.00000,1, 199062.10000, 253528652.00000, 31.78422, 970.09030, 435.94600, 555227.80000, 68.21578,1, 134571.40000, 192432878.00000, 294.71140, 421428.00000, 0.00000,0,1, 5.72000, 7520.24000, 5.72000, 180.48580, 0.00000,0,1, 4.50746, 7168.13700, 4.50746, 172.03530, 14000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 17239.80000, 11.80000, 413.75520,1, 7000.00000, 10227000.00000, 15.33000, 22397.13000,1, 9.75676, 8492.25000, 9.75676, 203.81400 -2024-12-01 00:00:00,1, 345398.60000, 570300752.00000, 32.36843, 1225.63500, 756.42290, 1248959.00000, 10000.00000,63.69638,10.12661,75.37705,11.98363, 32.36843, 1225.63500, 0.00000, 0.00000,1, 345398.60000, 570300752.00000, 32.36843, 1225.63500, 756.42290, 1248959.00000, 10000.00000,63.69638,10.12661,75.37705,11.98363, 32.36843, 1225.63500, 0.00000, 0.00000, 1.00000,1, 202684.30000, 320214456.00000, 32.36843, 1225.63500, 443.87860, 701269.70000, 67.63157,1, 135714.30000, 237514297.00000, 297.21430, 520156.30000, 0.00000,0,1, 6.13000, 9436.44000, 6.13000, 226.47460, 0.00000,0,1, 4.68168, 8678.13600, 4.68168, 208.27530, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 21192.80000, 11.80000, 508.62720,1, 7000.00000, 12572000.00000, 15.33000, 27532.68000,1, 9.75676, 11760.76000, 9.75676, 282.25830 -2026-01-01 00:00:00,1, 346729.90000, 707078598.00000, 32.39884, 1533.26500, 759.33840, 1548502.00000, 11100.00000,65.70359,10.44572,68.40886,10.87581, 32.39884, 1533.26500, 0.00000, 0.00000,1, 346729.90000, 707078598.00000, 32.39884, 1533.26500, 759.33840, 1548502.00000, 11100.00000,65.70359,10.44572,68.40886,10.87581, 32.39884, 1533.26500, 0.00000, 0.00000, 1.00000,1, 202872.80000, 400477438.00000, 32.39884, 1533.26500, 444.29140, 877045.60000, 67.60116,1, 136857.10000, 291257160.00000, 299.71700, 637853.20000, 0.00000,0,1, 6.25000, 11863.92000, 6.25000, 284.73410, 0.00000,0,1, 5.02452, 10532.08000, 5.02452, 252.76990, 17000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 25865.60000, 11.80000, 620.77440,1, 7000.00000, 15344000.00000, 15.33000, 33603.36000,1, 9.32432, 15624.44000, 9.32432, 374.98650 -2027-01-01 00:00:00,1, 355282.00000, 833635012.00000, 33.04086, 1817.07900, 778.06750, 1825661.00000, 10500.00000,66.10042,10.50881,74.10167,11.78087, 33.04086, 1817.07900, 0.00000, 0.00000,1, 355282.00000, 833635012.00000, 33.04086, 1817.07900, 778.06750, 1825661.00000, 10500.00000,66.10042,10.50881,74.10167,11.78087, 33.04086, 1817.07900, 0.00000, 0.00000, 1.00000,1, 206853.40000, 474526010.00000, 33.04086, 1817.07900, 453.00890, 1039212.00000, 66.95914,1, 141428.60000, 341210001.00000, 309.72860, 747249.90000, 0.00000,0,1, 6.37000, 14145.17000, 6.37000, 339.48410, 0.00000,0,1, 4.68168, 12366.03000, 4.68168, 296.78470, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 30172.60000, 11.80000, 724.14240,1, 7000.00000, 17899000.00000, 15.33000, 39198.81000,1, 10.18919, 19027.82000, 10.18919, 456.66760 -2028-01-01 00:00:00,1, 339026.40000, 963312942.00000, 32.26232, 2106.51700, 742.46780, 2109655.00000, 9500.00000,67.07539,10.66381,78.15451,12.4252, 32.26232, 2106.51700, 0.00000, 0.00000,1, 339026.40000, 963312942.00000, 32.26232, 2106.51700, 742.46780, 2109655.00000, 9500.00000,67.07539,10.66381,78.15451,12.4252, 32.26232, 2106.51700, 0.00000, 0.00000, 1.00000,1, 202026.40000, 550027501.00000, 32.26232, 2106.51700, 442.43780, 1204560.00000, 67.73768,1, 130000.00000, 392831440.00000, 284.70000, 860300.80000, 0.00000,0,1, 6.52000, 16470.22000, 6.52000, 395.28530, 0.00000,0,1, 4.18557, 14074.84000, 4.18557, 337.79620, 12000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 34479.60000, 11.80000, 827.51040,1, 7000.00000, 20454000.00000, 15.33000, 44794.26000,1, 9.75676, 22746.87000, 9.75676, 545.92490 -2029-01-01 00:00:00,1, 263106.70000, 1087396604.00000, 32.92043, 2389.90900, 576.20370, 2381399.00000, 7500.00000,68.17826,10.83915,76.82716,12.21417, 32.92043, 2389.90900, 0.00000, 0.00000,1, 263106.70000, 1087396604.00000, 32.92043, 2389.90900, 576.20370, 2381399.00000, 7500.00000,68.17826,10.83915,76.82716,12.21417, 32.92043, 2389.90900, 0.00000, 0.00000, 1.00000,1, 206106.70000, 623969164.00000, 32.92043, 2389.90900, 451.37370, 1366492.00000, 67.07957,1, 50000.00000, 440411440.00000, 109.50000, 964501.00000, 0.00000,0,1, 6.64000, 18856.54000, 6.64000, 452.55700, 0.00000,0,1, 4.50746, 15606.76000, 4.50746, 374.56220, 14000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 38798.40000, 11.80000, 931.16160,1, 7000.00000, 23016000.00000, 15.33000, 50405.04000,1, 9.97297, 26317.85000, 9.97297, 631.62830 -2030-01-01 00:00:00,1, 262298.20000, 1183430550.00000, 32.79003, 2678.29200, 574.43310, 2591713.00000, 8000.00000,68.80684,10.93908,71.80414,11.4156, 32.79003, 2678.29200, 0.00000, 0.00000,1, 262298.20000, 1183430550.00000, 32.79003, 2678.29200, 574.43310, 2591713.00000, 8000.00000,68.80684,10.93908,71.80414,11.4156, 32.79003, 2678.29200, 0.00000, 0.00000, 1.00000,1, 205298.20000, 699198109.00000, 32.79003, 2678.29200, 449.60310, 1531244.00000, 67.20997,1, 50000.00000, 458661440.00000, 109.50000, 1004469.00000, 0.00000,0,1, 6.80000, 21280.14000, 6.80000, 510.72340, 0.00000,0,1, 4.86570, 17251.98000, 4.86570, 414.04750, 16000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 43105.40000, 11.80000, 1034.53000,1, 7000.00000, 25571000.00000, 15.33000, 56000.49000,1, 9.32432, 29957.98000, 9.32432, 718.99150 -2031-01-01 00:00:00,1, 260635.10000, 1279169392.00000, 32.52178, 2965.53300, 570.79090, 2801381.00000, 7000.00000,69.02248,10.97337,nan,nan, 32.52178, 2965.53300, 0.00000, 0.00000,1, 260635.10000, 1279169392.00000, 32.52178, 2965.53300, 570.79090, 2801381.00000, 7000.00000,69.02248,10.97337,nan,nan, 32.52178, 2965.53300, 0.00000, 0.00000, 1.00000,1, 203635.10000, 774131952.00000, 32.52178, 2965.53300, 445.96090, 1695349.00000, 67.47822,1, 50000.00000, 476911440.00000, 109.50000, 1044436.00000, 0.00000,0,1, 6.89000, 23762.14000, 6.89000, 570.29140, 0.00000,0,1, 4.50746, 19027.96000, 4.50746, 456.67100, 14000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 47412.40000, 11.80000, 1137.89800,1, 7000.00000, 28126000.00000, 15.33000, 61595.94000,1, 9.32432, 33361.36000, 9.32432, 800.67260 +2021-01-01 00:00:00,1, 311343.90000, 113763780.00000, 27.61307, 243.44430, 681.84320, 249142.70000, 11600.00000,54.45742,8.657777,58.77959,9.344926, 27.61307, 243.44430, 0.00000, 0.00000,1, 311343.90000, 113763780.00000, 27.61307, 243.44430, 681.84320, 249142.70000, 11600.00000,54.45742,8.657777,58.77959,9.344926, 27.61307, 243.44430, 0.00000, 0.00000, 1.00000,1, 173201.00000, 63621780.00000, 27.61307, 243.44430, 379.31030, 139331.70000, 72.38693,1, 131142.90000, 47580000.00000, 287.20290, 104200.20000, 0.00000,0,1, 5.01000, 1789.74000, 5.01000, 42.95376, 0.00000,0,1, 5.05307, 1838.97300, 5.05307, 44.13536, 17200.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 4318.80000, 11.80000, 103.65120,1, 7000.00000, 2562000.00000, 15.33000, 5610.78000,1, 5.75000, 2196.00000, 5.75000, 52.70400 +2022-01-01 00:00:00,1, 309378.10000, 227404304.00000, 27.11168, 485.33480, 677.53800, 498015.40000, 10700.00000,56.53484,8.988052,63.32131,10.06698, 27.11168, 485.33480, 0.00000, 0.00000,1, 309378.10000, 227404304.00000, 27.11168, 485.33480, 677.53800, 498015.40000, 10700.00000,56.53484,8.988052,63.32131,10.06698, 27.11168, 485.33480, 0.00000, 0.00000, 1.00000,1, 170092.40000, 126840145.00000, 27.11168, 485.33480, 372.50230, 277780.00000, 72.88832,1, 132285.70000, 95447158.00000, 289.70570, 209029.30000, 0.00000,0,1, 5.13000, 3618.39000, 5.13000, 86.84136, 0.00000,0,1, 4.68168, 3683.34500, 4.68168, 88.40027, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 8625.80000, 11.80000, 207.01920,1, 7000.00000, 5117000.00000, 15.33000, 11206.23000,1, 5.50000, 4294.75000, 5.50000, 103.07400 +2023-01-01 00:00:00,1, 317428.00000, 340327310.00000, 28.22570, 722.83320, 695.16720, 745316.80000, 9800.00000,58.61944,9.319465,70.93543,11.27749, 28.22570, 722.83320, 0.00000, 0.00000,1, 317428.00000, 340327310.00000, 28.22570, 722.83320, 695.16720, 745316.80000, 9800.00000,58.61944,9.319465,70.93543,11.27749, 28.22570, 722.83320, 0.00000, 0.00000, 1.00000,1, 176999.40000, 188923871.00000, 28.22570, 722.83320, 387.62860, 413743.30000, 71.77430,1, 133428.60000, 143731439.00000, 292.20860, 314771.80000, 0.00000,0,1, 5.56000, 5490.84000, 5.56000, 131.78020, 0.00000,0,1, 4.86570, 5392.15600, 4.86570, 129.41170, 16000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 12932.80000, 11.80000, 310.38720,1, 7000.00000, 7672000.00000, 15.33000, 16801.68000,1, 6.00000, 6302.25000, 6.00000, 151.25400 +2024-01-01 00:00:00,1, 340633.50000, 456188530.00000, 31.78422, 970.09030, 745.98750, 999052.80000, 9900.00000,61.32356,9.749374,75.37706,11.98363, 31.78422, 970.09030, 0.00000, 0.00000,1, 340633.50000, 456188530.00000, 31.78422, 970.09030, 745.98750, 999052.80000, 9900.00000,61.32356,9.749374,75.37706,11.98363, 31.78422, 970.09030, 0.00000, 0.00000, 1.00000,1, 199062.10000, 253528652.00000, 31.78422, 970.09030, 435.94610, 555227.70000, 68.21578,1, 134571.40000, 192432878.00000, 294.71140, 421428.00000, 0.00000,0,1, 5.72000, 7520.24000, 5.72000, 180.48580, 0.00000,0,1, 4.50746, 7168.13700, 4.50746, 172.03530, 14000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 17239.80000, 11.80000, 413.75520,1, 7000.00000, 10227000.00000, 15.33000, 22397.13000,1, 9.75676, 8492.25000, 9.75676, 203.81400 +2024-12-01 00:00:00,1, 345398.60000, 570300752.00000, 32.36843, 1225.63500, 756.42290, 1248959.00000, 10000.00000,63.69638,10.12661,75.37706,11.98363, 32.36843, 1225.63500, 0.00000, 0.00000,1, 345398.60000, 570300752.00000, 32.36843, 1225.63500, 756.42290, 1248959.00000, 10000.00000,63.69638,10.12661,75.37706,11.98363, 32.36843, 1225.63500, 0.00000, 0.00000, 1.00000,1, 202684.30000, 320214456.00000, 32.36843, 1225.63500, 443.87860, 701269.70000, 67.63157,1, 135714.30000, 237514297.00000, 297.21430, 520156.30000, 0.00000,0,1, 6.13000, 9436.44000, 6.13000, 226.47460, 0.00000,0,1, 4.68168, 8678.13600, 4.68168, 208.27530, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 21192.80000, 11.80000, 508.62720,1, 7000.00000, 12572000.00000, 15.33000, 27532.68000,1, 9.75676, 11760.76000, 9.75676, 282.25830 +2026-01-01 00:00:00,1, 346729.90000, 707078598.00000, 32.39884, 1533.26500, 759.33860, 1548502.00000, 11100.00000,65.70359,10.44572,68.40888,10.87582, 32.39884, 1533.26500, 0.00000, 0.00000,1, 346729.90000, 707078598.00000, 32.39884, 1533.26500, 759.33860, 1548502.00000, 11100.00000,65.70359,10.44572,68.40888,10.87582, 32.39884, 1533.26500, 0.00000, 0.00000, 1.00000,1, 202872.80000, 400477438.00000, 32.39884, 1533.26500, 444.29150, 877045.60000, 67.60116,1, 136857.10000, 291257160.00000, 299.71710, 637853.20000, 0.00000,0,1, 6.25000, 11863.92000, 6.25000, 284.73410, 0.00000,0,1, 5.02452, 10532.08000, 5.02452, 252.76990, 17000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 25865.60000, 11.80000, 620.77440,1, 7000.00000, 15344000.00000, 15.33000, 33603.36000,1, 9.32432, 15624.44000, 9.32432, 374.98650 +2027-01-01 00:00:00,1, 355282.00000, 833635012.00000, 33.04086, 1817.07900, 778.06750, 1825661.00000, 10500.00000,66.10043,10.50881,74.10167,11.78087, 33.04086, 1817.07900, 0.00000, 0.00000,1, 355282.00000, 833635012.00000, 33.04086, 1817.07900, 778.06750, 1825661.00000, 10500.00000,66.10043,10.50881,74.10167,11.78087, 33.04086, 1817.07900, 0.00000, 0.00000, 1.00000,1, 206853.40000, 474526010.00000, 33.04086, 1817.07900, 453.00890, 1039212.00000, 66.95914,1, 141428.60000, 341210001.00000, 309.72860, 747249.90000, 0.00000,0,1, 6.37000, 14145.17000, 6.37000, 339.48410, 0.00000,0,1, 4.68168, 12366.03000, 4.68168, 296.78470, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 30172.60000, 11.80000, 724.14240,1, 7000.00000, 17899000.00000, 15.33000, 39198.81000,1, 10.18919, 19027.82000, 10.18919, 456.66760 +2028-01-01 00:00:00,1, 339026.40000, 963312942.00000, 32.26232, 2106.51700, 742.46780, 2109655.00000, 9500.00000,67.0754,10.66381,78.15451,12.4252, 32.26232, 2106.51700, 0.00000, 0.00000,1, 339026.40000, 963312942.00000, 32.26232, 2106.51700, 742.46780, 2109655.00000, 9500.00000,67.0754,10.66381,78.15451,12.4252, 32.26232, 2106.51700, 0.00000, 0.00000, 1.00000,1, 202026.40000, 550027501.00000, 32.26232, 2106.51700, 442.43780, 1204560.00000, 67.73768,1, 130000.00000, 392831440.00000, 284.70000, 860300.80000, 0.00000,0,1, 6.52000, 16470.22000, 6.52000, 395.28530, 0.00000,0,1, 4.18557, 14074.84000, 4.18557, 337.79620, 12000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 34479.60000, 11.80000, 827.51040,1, 7000.00000, 20454000.00000, 15.33000, 44794.26000,1, 9.75676, 22746.87000, 9.75676, 545.92490 +2029-01-01 00:00:00,1, 263106.70000, 1087396604.00000, 32.92043, 2389.90900, 576.20360, 2381399.00000, 7500.00000,68.17826,10.83915,76.82715,12.21417, 32.92043, 2389.90900, 0.00000, 0.00000,1, 263106.70000, 1087396604.00000, 32.92043, 2389.90900, 576.20360, 2381399.00000, 7500.00000,68.17826,10.83915,76.82715,12.21417, 32.92043, 2389.90900, 0.00000, 0.00000, 1.00000,1, 206106.70000, 623969164.00000, 32.92043, 2389.90900, 451.37360, 1366492.00000, 67.07957,1, 50000.00000, 440411440.00000, 109.50000, 964501.00000, 0.00000,0,1, 6.64000, 18856.54000, 6.64000, 452.55700, 0.00000,0,1, 4.50746, 15606.76000, 4.50746, 374.56220, 14000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 38798.40000, 11.80000, 931.16160,1, 7000.00000, 23016000.00000, 15.33000, 50405.04000,1, 9.97297, 26317.85000, 9.97297, 631.62830 +2030-01-01 00:00:00,1, 262298.20000, 1183430550.00000, 32.79003, 2678.29200, 574.43300, 2591713.00000, 8000.00000,68.80684,10.93908,71.80412,11.4156, 32.79003, 2678.29200, 0.00000, 0.00000,1, 262298.20000, 1183430550.00000, 32.79003, 2678.29200, 574.43300, 2591713.00000, 8000.00000,68.80684,10.93908,71.80412,11.4156, 32.79003, 2678.29200, 0.00000, 0.00000, 1.00000,1, 205298.20000, 699198109.00000, 32.79003, 2678.29200, 449.60300, 1531244.00000, 67.20997,1, 50000.00000, 458661440.00000, 109.50000, 1004469.00000, 0.00000,0,1, 6.80000, 21280.14000, 6.80000, 510.72340, 0.00000,0,1, 4.86570, 17251.98000, 4.86570, 414.04750, 16000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 43105.40000, 11.80000, 1034.53000,1, 7000.00000, 25571000.00000, 15.33000, 56000.49000,1, 9.32432, 29957.98000, 9.32432, 718.99150 +2031-01-01 00:00:00,1, 260635.10000, 1279169392.00000, 32.52178, 2965.53300, 570.79080, 2801381.00000, 7000.00000,69.02248,10.97337,nan,nan, 32.52178, 2965.53300, 0.00000, 0.00000,1, 260635.10000, 1279169392.00000, 32.52178, 2965.53300, 570.79080, 2801381.00000, 7000.00000,69.02248,10.97337,nan,nan, 32.52178, 2965.53300, 0.00000, 0.00000, 1.00000,1, 203635.10000, 774131952.00000, 32.52178, 2965.53300, 445.96080, 1695349.00000, 67.47822,1, 50000.00000, 476911440.00000, 109.50000, 1044436.00000, 0.00000,0,1, 6.89000, 23762.14000, 6.89000, 570.29140, 0.00000,0,1, 4.50746, 19027.96000, 4.50746, 456.67100, 14000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 47412.40000, 11.80000, 1137.89800,1, 7000.00000, 28126000.00000, 15.33000, 61595.94000,1, 9.32432, 33361.36000, 9.32432, 800.67260 diff --git a/src/tests/ecalc_cli/snapshots/test_app/test_csv_temporal_default/test.csv b/src/tests/ecalc_cli/snapshots/test_app/test_csv_temporal_default/test.csv index f88e352b2c..234b1e666c 100644 --- a/src/tests/ecalc_cli/snapshots/test_app/test_csv_temporal_default/test.csv +++ b/src/tests/ecalc_cli/snapshots/test_app/test_csv_temporal_default/test.csv @@ -1,14 +1,14 @@ timesteps,model.is_valid[N/A],model.energy_usage[Sm3/cd],model.energy_usage_cumulative[Sm3 (cd)],model.power[MW (sd)],model.power_cumulative[GWh (cd)],model.co2.rate[t/cd],model.co2.cumulative[t (cd)],model.hydrocarbon_export_rate[Sm3/cd],model.co2.intensity_sm3[kg/Sm3],model.co2.intensity_boe[kg/BOE],model.co2.intensity_yearly_sm3[kg/Sm3],model.co2.intensity_yearly_boe[kg/BOE],model.power_electrical[MW (sd)],model.power_electrical_cumulative[GWh (cd)],model.power_mechanical[MW (sd)],model.power_mechanical_cumulative[GWh (cd)],Installation A.is_valid[N/A],Installation A.energy_usage[Sm3/cd],Installation A.energy_usage_cumulative[Sm3 (cd)],Installation A.power[MW (sd)],Installation A.power_cumulative[GWh (cd)],Installation A.co2.rate[t/cd],Installation A.co2.cumulative[t (cd)],Installation A.hydrocarbon_export_rate[Sm3/cd],Installation A.co2.intensity_sm3[kg/Sm3],Installation A.co2.intensity_boe[kg/BOE],Installation A.co2.intensity_yearly_sm3[kg/Sm3],Installation A.co2.intensity_yearly_boe[kg/BOE],Installation A.power_electrical[MW (sd)],Installation A.power_electrical_cumulative[GWh (cd)],Installation A.power_mechanical[MW (sd)],Installation A.power_mechanical_cumulative[GWh (cd)],Installation A.regularity[N/A],Generator set A.is_valid[N/A],Generator set A.energy_usage[Sm3/cd],Generator set A.energy_usage_cumulative[Sm3 (cd)],Generator set A.power[MW (sd)],Generator set A.power_cumulative[GWh (cd)],Generator set A.co2.rate[t/cd],Generator set A.co2.cumulative[t (cd)],Generator set A.power_capacity_margin[MW (sd)],Gas export compressor.is_valid[N/A],Gas export compressor.energy_usage[Sm3/cd],Gas export compressor.energy_usage_cumulative[Sm3 (cd)],Gas export compressor.co2.rate[t/cd],Gas export compressor.co2.cumulative[t (cd)],Gas export compressor.recirculation_loss[MW (sd)],Gas export compressor.rate_exceeds_maximum[N/A],Gas injection compressor.is_valid[N/A],Gas injection compressor.energy_usage[MW (sd)],Gas injection compressor.energy_usage_cumulative[MWd (cd)],Gas injection compressor.power[MW (sd)],Gas injection compressor.power_cumulative[GWh (cd)],Gas injection compressor.recirculation_loss[MW (sd)],Gas injection compressor.rate_exceeds_maximum[N/A],Produced water reinjection pump.is_valid[N/A],Produced water reinjection pump.energy_usage[MW (sd)],Produced water reinjection pump.energy_usage_cumulative[MWd (cd)],Produced water reinjection pump.power[MW (sd)],Produced water reinjection pump.power_cumulative[GWh (cd)],Produced water reinjection pump.inlet_liquid_rate_m3_per_day[Sm3/sd],Produced water reinjection pump.inlet_pressure_bar[bara],Produced water reinjection pump.outlet_pressure_bar[bara],Produced water reinjection pump.operational_head[J/kg],Base production load.is_valid[N/A],Base production load.energy_usage[MW (sd)],Base production load.energy_usage_cumulative[MWd (cd)],Base production load.power[MW (sd)],Base production load.power_cumulative[GWh (cd)],Flare.is_valid[N/A],Flare.energy_usage[Sm3/cd],Flare.energy_usage_cumulative[Sm3 (cd)],Flare.co2.rate[t/cd],Flare.co2.cumulative[t (cd)],Sea water injection pump.is_valid[N/A],Sea water injection pump.energy_usage[MW (sd)],Sea water injection pump.energy_usage_cumulative[MWd (cd)],Sea water injection pump.power[MW (sd)],Sea water injection pump.power_cumulative[GWh (cd)] 2020-01-01 00:00:00,1, 310830.00000, 0.00000, 27.71452, 0.00000, 680.71770, 0.00000, 12500.00000,nan,nan,54.45742,8.657777, 27.71452, 0.00000, 0.00000, 0.00000,1, 310830.00000, 0.00000, 27.71452, 0.00000, 680.71770, 0.00000, 12500.00000,nan,nan,54.45742,8.657777, 27.71452, 0.00000, 0.00000, 0.00000, 1.00000,1, 173830.00000, 0.00000, 27.71452, 0.00000, 380.68770, 0.00000, 72.28548,1, 130000.00000, 0.00000, 284.70000, 0.00000, 0.00000,0,1, 4.89000, 0.00000, 4.89000, 0.00000, 0.00000,0,1, 5.02452, 0.00000, 5.02452, 0.00000, 17000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 0.00000, 11.80000, 0.00000,1, 7000.00000, 0.00000, 15.33000, 0.00000,1, 6.00000, 0.00000, 6.00000, 0.00000 -2021-01-01 00:00:00,1, 311343.90000, 113763780.00000, 27.61307, 243.44430, 681.84320, 249142.70000, 11600.00000,54.45742,8.657777,58.77959,9.344926, 27.61307, 243.44430, 0.00000, 0.00000,1, 311343.90000, 113763780.00000, 27.61307, 243.44430, 681.84320, 249142.70000, 11600.00000,54.45742,8.657777,58.77959,9.344926, 27.61307, 243.44430, 0.00000, 0.00000, 1.00000,1, 173201.00000, 63621780.00000, 27.61307, 243.44430, 379.31020, 139331.70000, 72.38693,1, 131142.90000, 47580000.00000, 287.20300, 104200.20000, 0.00000,0,1, 5.01000, 1789.74000, 5.01000, 42.95376, 0.00000,0,1, 5.05307, 1838.97300, 5.05307, 44.13536, 17200.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 4318.80000, 11.80000, 103.65120,1, 7000.00000, 2562000.00000, 15.33000, 5610.78000,1, 5.75000, 2196.00000, 5.75000, 52.70400 -2022-01-01 00:00:00,1, 309378.10000, 227404304.00000, 27.11168, 485.33480, 677.53810, 498015.40000, 10700.00000,56.53484,8.988052,63.32132,10.06698, 27.11168, 485.33480, 0.00000, 0.00000,1, 309378.10000, 227404304.00000, 27.11168, 485.33480, 677.53810, 498015.40000, 10700.00000,56.53484,8.988052,63.32132,10.06698, 27.11168, 485.33480, 0.00000, 0.00000, 1.00000,1, 170092.40000, 126840145.00000, 27.11168, 485.33480, 372.50240, 277779.90000, 72.88832,1, 132285.70000, 95447158.00000, 289.70570, 209029.30000, 0.00000,0,1, 5.13000, 3618.39000, 5.13000, 86.84136, 0.00000,0,1, 4.68168, 3683.34500, 4.68168, 88.40027, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 8625.80000, 11.80000, 207.01920,1, 7000.00000, 5117000.00000, 15.33000, 11206.23000,1, 5.50000, 4294.75000, 5.50000, 103.07400 -2023-01-01 00:00:00,1, 317428.00000, 340327310.00000, 28.22570, 722.83320, 695.16730, 745316.90000, 9800.00000,58.61944,9.319466,70.93544,11.27749, 28.22570, 722.83320, 0.00000, 0.00000,1, 317428.00000, 340327310.00000, 28.22570, 722.83320, 695.16730, 745316.90000, 9800.00000,58.61944,9.319466,70.93544,11.27749, 28.22570, 722.83320, 0.00000, 0.00000, 1.00000,1, 176999.40000, 188923871.00000, 28.22570, 722.83320, 387.62870, 413743.30000, 71.77430,1, 133428.60000, 143731439.00000, 292.20860, 314771.90000, 0.00000,0,1, 5.56000, 5490.84000, 5.56000, 131.78020, 0.00000,0,1, 4.86570, 5392.15600, 4.86570, 129.41170, 16000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 12932.80000, 11.80000, 310.38720,1, 7000.00000, 7672000.00000, 15.33000, 16801.68000,1, 6.00000, 6302.25000, 6.00000, 151.25400 -2024-01-01 00:00:00,1, 341037.10000, 456188530.00000, 31.83370, 970.09030, 746.87130, 999052.90000, 9908.47000,61.32357,9.749375,75.37705,11.98363, 31.83370, 970.09030, 0.00000, 0.00000,1, 341037.10000, 456188530.00000, 31.83370, 970.09030, 746.87130, 999052.90000, 9908.47000,61.32357,9.749375,75.37705,11.98363, 31.83370, 970.09030, 0.00000, 0.00000, 1.00000,1, 199368.90000, 253528652.00000, 31.83370, 970.09030, 436.61790, 555227.80000, 68.16630,1, 134668.20000, 192432878.00000, 294.92340, 421428.00000, 0.00000,0,1, 5.75473, 7520.24000, 5.75473, 180.48580, 0.00000,0,1, 4.52221, 7168.13700, 4.52221, 172.03530, 14084.70000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 17239.80000, 11.80000, 413.75520,1, 7000.00000, 10227000.00000, 15.33000, 22397.13000,1, 9.75676, 8492.25000, 9.75676, 203.81400 -2025-01-01 00:00:00,1, 345398.60000, 581008109.00000, 32.36843, 1249.71800, 756.42290, 1272408.00000, 10000.00000,63.88231,10.15617,75.64229,12.0258, 32.36843, 1249.71800, 0.00000, 0.00000,1, 345398.60000, 581008109.00000, 32.36843, 1249.71800, 756.42290, 1272408.00000, 10000.00000,63.88231,10.15617,75.64229,12.0258, 32.36843, 1249.71800, 0.00000, 0.00000, 1.00000,1, 202684.30000, 326497669.00000, 32.36843, 1249.71800, 443.87860, 715029.90000, 67.63157,1, 135714.30000, 241721440.00000, 297.21430, 529370.00000, 0.00000,0,1, 6.13000, 9626.47000, 6.13000, 231.03530, 0.00000,0,1, 4.68168, 8823.26800, 4.68168, 211.75840, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 21558.60000, 11.80000, 517.40640,1, 7000.00000, 12789000.00000, 15.33000, 28007.91000,1, 9.75676, 12063.22000, 9.75676, 289.51740 -2026-01-01 00:00:00,1, 346729.90000, 707078598.00000, 32.39884, 1533.26500, 759.33840, 1548502.00000, 11100.00000,65.70359,10.44572,68.40886,10.87581, 32.39884, 1533.26500, 0.00000, 0.00000,1, 346729.90000, 707078598.00000, 32.39884, 1533.26500, 759.33840, 1548502.00000, 11100.00000,65.70359,10.44572,68.40886,10.87581, 32.39884, 1533.26500, 0.00000, 0.00000, 1.00000,1, 202872.80000, 400477438.00000, 32.39884, 1533.26500, 444.29140, 877045.60000, 67.60116,1, 136857.10000, 291257160.00000, 299.71700, 637853.20000, 0.00000,0,1, 6.25000, 11863.92000, 6.25000, 284.73410, 0.00000,0,1, 5.02452, 10532.08000, 5.02452, 252.76990, 17000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 25865.60000, 11.80000, 620.77440,1, 7000.00000, 15344000.00000, 15.33000, 33603.36000,1, 9.32432, 15624.44000, 9.32432, 374.98650 -2027-01-01 00:00:00,1, 355282.00000, 833635012.00000, 33.04086, 1817.07900, 778.06750, 1825661.00000, 10500.00000,66.10042,10.50881,74.10167,11.78087, 33.04086, 1817.07900, 0.00000, 0.00000,1, 355282.00000, 833635012.00000, 33.04086, 1817.07900, 778.06750, 1825661.00000, 10500.00000,66.10042,10.50881,74.10167,11.78087, 33.04086, 1817.07900, 0.00000, 0.00000, 1.00000,1, 206853.40000, 474526010.00000, 33.04086, 1817.07900, 453.00890, 1039212.00000, 66.95914,1, 141428.60000, 341210001.00000, 309.72860, 747249.90000, 0.00000,0,1, 6.37000, 14145.17000, 6.37000, 339.48410, 0.00000,0,1, 4.68168, 12366.03000, 4.68168, 296.78470, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 30172.60000, 11.80000, 724.14240,1, 7000.00000, 17899000.00000, 15.33000, 39198.81000,1, 10.18919, 19027.82000, 10.18919, 456.66760 -2028-01-01 00:00:00,1, 339026.40000, 963312942.00000, 32.26232, 2106.51700, 742.46780, 2109655.00000, 9500.00000,67.07539,10.66381,78.15451,12.4252, 32.26232, 2106.51700, 0.00000, 0.00000,1, 339026.40000, 963312942.00000, 32.26232, 2106.51700, 742.46780, 2109655.00000, 9500.00000,67.07539,10.66381,78.15451,12.4252, 32.26232, 2106.51700, 0.00000, 0.00000, 1.00000,1, 202026.40000, 550027501.00000, 32.26232, 2106.51700, 442.43780, 1204560.00000, 67.73768,1, 130000.00000, 392831440.00000, 284.70000, 860300.80000, 0.00000,0,1, 6.52000, 16470.22000, 6.52000, 395.28530, 0.00000,0,1, 4.18557, 14074.84000, 4.18557, 337.79620, 12000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 34479.60000, 11.80000, 827.51040,1, 7000.00000, 20454000.00000, 15.33000, 44794.26000,1, 9.75676, 22746.87000, 9.75676, 545.92490 -2029-01-01 00:00:00,1, 263106.70000, 1087396604.00000, 32.92043, 2389.90900, 576.20370, 2381399.00000, 7500.00000,68.17826,10.83915,76.82716,12.21417, 32.92043, 2389.90900, 0.00000, 0.00000,1, 263106.70000, 1087396604.00000, 32.92043, 2389.90900, 576.20370, 2381399.00000, 7500.00000,68.17826,10.83915,76.82716,12.21417, 32.92043, 2389.90900, 0.00000, 0.00000, 1.00000,1, 206106.70000, 623969164.00000, 32.92043, 2389.90900, 451.37370, 1366492.00000, 67.07957,1, 50000.00000, 440411440.00000, 109.50000, 964501.00000, 0.00000,0,1, 6.64000, 18856.54000, 6.64000, 452.55700, 0.00000,0,1, 4.50746, 15606.76000, 4.50746, 374.56220, 14000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 38798.40000, 11.80000, 931.16160,1, 7000.00000, 23016000.00000, 15.33000, 50405.04000,1, 9.97297, 26317.85000, 9.97297, 631.62830 -2030-01-01 00:00:00,1, 262298.20000, 1183430550.00000, 32.79003, 2678.29200, 574.43310, 2591713.00000, 8000.00000,68.80684,10.93908,71.80414,11.4156, 32.79003, 2678.29200, 0.00000, 0.00000,1, 262298.20000, 1183430550.00000, 32.79003, 2678.29200, 574.43310, 2591713.00000, 8000.00000,68.80684,10.93908,71.80414,11.4156, 32.79003, 2678.29200, 0.00000, 0.00000, 1.00000,1, 205298.20000, 699198109.00000, 32.79003, 2678.29200, 449.60310, 1531244.00000, 67.20997,1, 50000.00000, 458661440.00000, 109.50000, 1004469.00000, 0.00000,0,1, 6.80000, 21280.14000, 6.80000, 510.72340, 0.00000,0,1, 4.86570, 17251.98000, 4.86570, 414.04750, 16000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 43105.40000, 11.80000, 1034.53000,1, 7000.00000, 25571000.00000, 15.33000, 56000.49000,1, 9.32432, 29957.98000, 9.32432, 718.99150 -2031-01-01 00:00:00,1, 260635.10000, 1279169392.00000, 32.52178, 2965.53300, 570.79090, 2801381.00000, 7000.00000,69.02248,10.97337,81.54156,12.96368, 32.52178, 2965.53300, 0.00000, 0.00000,1, 260635.10000, 1279169392.00000, 32.52178, 2965.53300, 570.79090, 2801381.00000, 7000.00000,69.02248,10.97337,81.54156,12.96368, 32.52178, 2965.53300, 0.00000, 0.00000, 1.00000,1, 203635.10000, 774131952.00000, 32.52178, 2965.53300, 445.96090, 1695349.00000, 67.47822,1, 50000.00000, 476911440.00000, 109.50000, 1044436.00000, 0.00000,0,1, 6.89000, 23762.14000, 6.89000, 570.29140, 0.00000,0,1, 4.50746, 19027.96000, 4.50746, 456.67100, 14000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 47412.40000, 11.80000, 1137.89800,1, 7000.00000, 28126000.00000, 15.33000, 61595.94000,1, 9.32432, 33361.36000, 9.32432, 800.67260 +2021-01-01 00:00:00,1, 311343.90000, 113763780.00000, 27.61307, 243.44430, 681.84320, 249142.70000, 11600.00000,54.45742,8.657777,58.77959,9.344926, 27.61307, 243.44430, 0.00000, 0.00000,1, 311343.90000, 113763780.00000, 27.61307, 243.44430, 681.84320, 249142.70000, 11600.00000,54.45742,8.657777,58.77959,9.344926, 27.61307, 243.44430, 0.00000, 0.00000, 1.00000,1, 173201.00000, 63621780.00000, 27.61307, 243.44430, 379.31030, 139331.70000, 72.38693,1, 131142.90000, 47580000.00000, 287.20290, 104200.20000, 0.00000,0,1, 5.01000, 1789.74000, 5.01000, 42.95376, 0.00000,0,1, 5.05307, 1838.97300, 5.05307, 44.13536, 17200.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 4318.80000, 11.80000, 103.65120,1, 7000.00000, 2562000.00000, 15.33000, 5610.78000,1, 5.75000, 2196.00000, 5.75000, 52.70400 +2022-01-01 00:00:00,1, 309378.10000, 227404304.00000, 27.11168, 485.33480, 677.53800, 498015.40000, 10700.00000,56.53484,8.988052,63.32131,10.06698, 27.11168, 485.33480, 0.00000, 0.00000,1, 309378.10000, 227404304.00000, 27.11168, 485.33480, 677.53800, 498015.40000, 10700.00000,56.53484,8.988052,63.32131,10.06698, 27.11168, 485.33480, 0.00000, 0.00000, 1.00000,1, 170092.40000, 126840145.00000, 27.11168, 485.33480, 372.50230, 277780.00000, 72.88832,1, 132285.70000, 95447158.00000, 289.70570, 209029.30000, 0.00000,0,1, 5.13000, 3618.39000, 5.13000, 86.84136, 0.00000,0,1, 4.68168, 3683.34500, 4.68168, 88.40027, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 8625.80000, 11.80000, 207.01920,1, 7000.00000, 5117000.00000, 15.33000, 11206.23000,1, 5.50000, 4294.75000, 5.50000, 103.07400 +2023-01-01 00:00:00,1, 317428.00000, 340327310.00000, 28.22570, 722.83320, 695.16720, 745316.80000, 9800.00000,58.61944,9.319465,70.93543,11.27749, 28.22570, 722.83320, 0.00000, 0.00000,1, 317428.00000, 340327310.00000, 28.22570, 722.83320, 695.16720, 745316.80000, 9800.00000,58.61944,9.319465,70.93543,11.27749, 28.22570, 722.83320, 0.00000, 0.00000, 1.00000,1, 176999.40000, 188923871.00000, 28.22570, 722.83320, 387.62860, 413743.30000, 71.77430,1, 133428.60000, 143731439.00000, 292.20860, 314771.80000, 0.00000,0,1, 5.56000, 5490.84000, 5.56000, 131.78020, 0.00000,0,1, 4.86570, 5392.15600, 4.86570, 129.41170, 16000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 12932.80000, 11.80000, 310.38720,1, 7000.00000, 7672000.00000, 15.33000, 16801.68000,1, 6.00000, 6302.25000, 6.00000, 151.25400 +2024-01-01 00:00:00,1, 341037.10000, 456188530.00000, 31.83370, 970.09030, 746.87140, 999052.80000, 9908.47000,61.32356,9.749374,75.37706,11.98363, 31.83370, 970.09030, 0.00000, 0.00000,1, 341037.10000, 456188530.00000, 31.83370, 970.09030, 746.87140, 999052.80000, 9908.47000,61.32356,9.749374,75.37706,11.98363, 31.83370, 970.09030, 0.00000, 0.00000, 1.00000,1, 199368.90000, 253528652.00000, 31.83370, 970.09030, 436.61800, 555227.70000, 68.16630,1, 134668.20000, 192432878.00000, 294.92340, 421428.00000, 0.00000,0,1, 5.75473, 7520.24000, 5.75473, 180.48580, 0.00000,0,1, 4.52221, 7168.13700, 4.52221, 172.03530, 14084.70000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 17239.80000, 11.80000, 413.75520,1, 7000.00000, 10227000.00000, 15.33000, 22397.13000,1, 9.75676, 8492.25000, 9.75676, 203.81400 +2025-01-01 00:00:00,1, 345398.60000, 581008109.00000, 32.36843, 1249.71800, 756.42290, 1272408.00000, 10000.00000,63.88231,10.15617,75.64229,12.0258, 32.36843, 1249.71800, 0.00000, 0.00000,1, 345398.60000, 581008109.00000, 32.36843, 1249.71800, 756.42290, 1272408.00000, 10000.00000,63.88231,10.15617,75.64229,12.0258, 32.36843, 1249.71800, 0.00000, 0.00000, 1.00000,1, 202684.30000, 326497669.00000, 32.36843, 1249.71800, 443.87860, 715029.90000, 67.63157,1, 135714.30000, 241721440.00000, 297.21430, 529369.90000, 0.00000,0,1, 6.13000, 9626.47000, 6.13000, 231.03530, 0.00000,0,1, 4.68168, 8823.26800, 4.68168, 211.75840, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 21558.60000, 11.80000, 517.40640,1, 7000.00000, 12789000.00000, 15.33000, 28007.91000,1, 9.75676, 12063.22000, 9.75676, 289.51740 +2026-01-01 00:00:00,1, 346729.90000, 707078598.00000, 32.39884, 1533.26500, 759.33860, 1548502.00000, 11100.00000,65.70359,10.44572,68.40888,10.87582, 32.39884, 1533.26500, 0.00000, 0.00000,1, 346729.90000, 707078598.00000, 32.39884, 1533.26500, 759.33860, 1548502.00000, 11100.00000,65.70359,10.44572,68.40888,10.87582, 32.39884, 1533.26500, 0.00000, 0.00000, 1.00000,1, 202872.80000, 400477438.00000, 32.39884, 1533.26500, 444.29150, 877045.60000, 67.60116,1, 136857.10000, 291257160.00000, 299.71710, 637853.20000, 0.00000,0,1, 6.25000, 11863.92000, 6.25000, 284.73410, 0.00000,0,1, 5.02452, 10532.08000, 5.02452, 252.76990, 17000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 25865.60000, 11.80000, 620.77440,1, 7000.00000, 15344000.00000, 15.33000, 33603.36000,1, 9.32432, 15624.44000, 9.32432, 374.98650 +2027-01-01 00:00:00,1, 355282.00000, 833635012.00000, 33.04086, 1817.07900, 778.06750, 1825661.00000, 10500.00000,66.10043,10.50881,74.10167,11.78087, 33.04086, 1817.07900, 0.00000, 0.00000,1, 355282.00000, 833635012.00000, 33.04086, 1817.07900, 778.06750, 1825661.00000, 10500.00000,66.10043,10.50881,74.10167,11.78087, 33.04086, 1817.07900, 0.00000, 0.00000, 1.00000,1, 206853.40000, 474526010.00000, 33.04086, 1817.07900, 453.00890, 1039212.00000, 66.95914,1, 141428.60000, 341210001.00000, 309.72860, 747249.90000, 0.00000,0,1, 6.37000, 14145.17000, 6.37000, 339.48410, 0.00000,0,1, 4.68168, 12366.03000, 4.68168, 296.78470, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 30172.60000, 11.80000, 724.14240,1, 7000.00000, 17899000.00000, 15.33000, 39198.81000,1, 10.18919, 19027.82000, 10.18919, 456.66760 +2028-01-01 00:00:00,1, 339026.40000, 963312942.00000, 32.26232, 2106.51700, 742.46780, 2109655.00000, 9500.00000,67.0754,10.66381,78.15451,12.4252, 32.26232, 2106.51700, 0.00000, 0.00000,1, 339026.40000, 963312942.00000, 32.26232, 2106.51700, 742.46780, 2109655.00000, 9500.00000,67.0754,10.66381,78.15451,12.4252, 32.26232, 2106.51700, 0.00000, 0.00000, 1.00000,1, 202026.40000, 550027501.00000, 32.26232, 2106.51700, 442.43780, 1204560.00000, 67.73768,1, 130000.00000, 392831440.00000, 284.70000, 860300.80000, 0.00000,0,1, 6.52000, 16470.22000, 6.52000, 395.28530, 0.00000,0,1, 4.18557, 14074.84000, 4.18557, 337.79620, 12000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 34479.60000, 11.80000, 827.51040,1, 7000.00000, 20454000.00000, 15.33000, 44794.26000,1, 9.75676, 22746.87000, 9.75676, 545.92490 +2029-01-01 00:00:00,1, 263106.70000, 1087396604.00000, 32.92043, 2389.90900, 576.20360, 2381399.00000, 7500.00000,68.17826,10.83915,76.82715,12.21417, 32.92043, 2389.90900, 0.00000, 0.00000,1, 263106.70000, 1087396604.00000, 32.92043, 2389.90900, 576.20360, 2381399.00000, 7500.00000,68.17826,10.83915,76.82715,12.21417, 32.92043, 2389.90900, 0.00000, 0.00000, 1.00000,1, 206106.70000, 623969164.00000, 32.92043, 2389.90900, 451.37360, 1366492.00000, 67.07957,1, 50000.00000, 440411440.00000, 109.50000, 964501.00000, 0.00000,0,1, 6.64000, 18856.54000, 6.64000, 452.55700, 0.00000,0,1, 4.50746, 15606.76000, 4.50746, 374.56220, 14000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 38798.40000, 11.80000, 931.16160,1, 7000.00000, 23016000.00000, 15.33000, 50405.04000,1, 9.97297, 26317.85000, 9.97297, 631.62830 +2030-01-01 00:00:00,1, 262298.20000, 1183430550.00000, 32.79003, 2678.29200, 574.43300, 2591713.00000, 8000.00000,68.80684,10.93908,71.80412,11.4156, 32.79003, 2678.29200, 0.00000, 0.00000,1, 262298.20000, 1183430550.00000, 32.79003, 2678.29200, 574.43300, 2591713.00000, 8000.00000,68.80684,10.93908,71.80412,11.4156, 32.79003, 2678.29200, 0.00000, 0.00000, 1.00000,1, 205298.20000, 699198109.00000, 32.79003, 2678.29200, 449.60300, 1531244.00000, 67.20997,1, 50000.00000, 458661440.00000, 109.50000, 1004469.00000, 0.00000,0,1, 6.80000, 21280.14000, 6.80000, 510.72340, 0.00000,0,1, 4.86570, 17251.98000, 4.86570, 414.04750, 16000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 43105.40000, 11.80000, 1034.53000,1, 7000.00000, 25571000.00000, 15.33000, 56000.49000,1, 9.32432, 29957.98000, 9.32432, 718.99150 +2031-01-01 00:00:00,1, 260635.10000, 1279169392.00000, 32.52178, 2965.53300, 570.79080, 2801381.00000, 7000.00000,69.02248,10.97337,81.54154,12.96368, 32.52178, 2965.53300, 0.00000, 0.00000,1, 260635.10000, 1279169392.00000, 32.52178, 2965.53300, 570.79080, 2801381.00000, 7000.00000,69.02248,10.97337,81.54154,12.96368, 32.52178, 2965.53300, 0.00000, 0.00000, 1.00000,1, 203635.10000, 774131952.00000, 32.52178, 2965.53300, 445.96080, 1695349.00000, 67.47822,1, 50000.00000, 476911440.00000, 109.50000, 1044436.00000, 0.00000,0,1, 6.89000, 23762.14000, 6.89000, 570.29140, 0.00000,0,1, 4.50746, 19027.96000, 4.50746, 456.67100, 14000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 47412.40000, 11.80000, 1137.89800,1, 7000.00000, 28126000.00000, 15.33000, 61595.94000,1, 9.32432, 33361.36000, 9.32432, 800.67260 2032-01-01 00:00:00,1, 0.00000, 1374301204.00000, 0.00000, 3250.42300, 0.00000, 3009720.00000, 0.00000,69.76391,11.09124,nan,nan, 0.00000, 3250.42300, 0.00000, 0.00000,1, 0.00000, 1374301204.00000, 0.00000, 3250.42300, 0.00000, 3009720.00000, 0.00000,69.76391,11.09124,nan,nan, 0.00000, 3250.42300, 0.00000, 0.00000, 1.00000,1, 0.00000, 848458764.00000, 0.00000, 3250.42300, 0.00000, 1858125.00000, 0.00000,1, 0.00000, 495161440.00000, 0.00000, 1084404.00000, 0.00000,0,1, 0.00000, 26276.99000, 0.00000, 630.64780, 0.00000,0,1, 0.00000, 20673.18000, 0.00000, 496.15640, 0.00000, 10.00000, 200.00000, 18811.88000,1, 0.00000, 51719.40000, 0.00000, 1241.26600,1, 0.00000, 30681000.00000, 0.00000, 67191.39000,1, 0.00000, 36764.74000, 0.00000, 882.35370 diff --git a/src/tests/ecalc_cli/snapshots/test_app/test_csv_temporal_default/test_temporal.csv b/src/tests/ecalc_cli/snapshots/test_app/test_csv_temporal_default/test_temporal.csv index 15432ea72f..7d0ca8812b 100644 --- a/src/tests/ecalc_cli/snapshots/test_app/test_csv_temporal_default/test_temporal.csv +++ b/src/tests/ecalc_cli/snapshots/test_app/test_csv_temporal_default/test_temporal.csv @@ -1,14 +1,14 @@ timesteps,model_temporal.is_valid[N/A],model_temporal.energy_usage[Sm3/cd],model_temporal.energy_usage_cumulative[Sm3 (cd)],model_temporal.power[MW (sd)],model_temporal.power_cumulative[GWh (cd)],model_temporal.co2.rate[t/cd],model_temporal.co2.cumulative[t (cd)],model_temporal.hydrocarbon_export_rate[Sm3/cd],model_temporal.co2.intensity_sm3[kg/Sm3],model_temporal.co2.intensity_boe[kg/BOE],model_temporal.co2.intensity_yearly_sm3[kg/Sm3],model_temporal.co2.intensity_yearly_boe[kg/BOE],model_temporal.power_electrical[MW (sd)],model_temporal.power_electrical_cumulative[GWh (cd)],model_temporal.power_mechanical[MW (sd)],model_temporal.power_mechanical_cumulative[GWh (cd)],Installation A.is_valid[N/A],Installation A.energy_usage[Sm3/cd],Installation A.energy_usage_cumulative[Sm3 (cd)],Installation A.power[MW (sd)],Installation A.power_cumulative[GWh (cd)],Installation A.co2.rate[t/cd],Installation A.co2.cumulative[t (cd)],Installation A.hydrocarbon_export_rate[Sm3/cd],Installation A.co2.intensity_sm3[kg/Sm3],Installation A.co2.intensity_boe[kg/BOE],Installation A.co2.intensity_yearly_sm3[kg/Sm3],Installation A.co2.intensity_yearly_boe[kg/BOE],Installation A.power_electrical[MW (sd)],Installation A.power_electrical_cumulative[GWh (cd)],Installation A.power_mechanical[MW (sd)],Installation A.power_mechanical_cumulative[GWh (cd)],Installation A.regularity[N/A],Generator set A.is_valid[N/A],Generator set A.energy_usage[Sm3/cd],Generator set A.energy_usage_cumulative[Sm3 (cd)],Generator set A.power[MW (sd)],Generator set A.power_cumulative[GWh (cd)],Generator set A.co2.rate[t/cd],Generator set A.co2.cumulative[t (cd)],Generator set A.power_capacity_margin[MW (sd)],Gas export compressor.is_valid[N/A],Gas export compressor.energy_usage[Sm3/cd],Gas export compressor.energy_usage_cumulative[Sm3 (cd)],Gas export compressor.co2.rate[t/cd],Gas export compressor.co2.cumulative[t (cd)],Gas export compressor.recirculation_loss[MW (sd)],Gas export compressor.rate_exceeds_maximum[N/A],Gas injection compressor.is_valid[N/A],Gas injection compressor.energy_usage[MW (sd)],Gas injection compressor.energy_usage_cumulative[MWd (cd)],Gas injection compressor.power[MW (sd)],Gas injection compressor.power_cumulative[GWh (cd)],Gas injection compressor.recirculation_loss[MW (sd)],Gas injection compressor.rate_exceeds_maximum[N/A],Produced water reinjection pump.is_valid[N/A],Produced water reinjection pump.energy_usage[MW (sd)],Produced water reinjection pump.energy_usage_cumulative[MWd (cd)],Produced water reinjection pump.power[MW (sd)],Produced water reinjection pump.power_cumulative[GWh (cd)],Produced water reinjection pump.inlet_liquid_rate_m3_per_day[Sm3/sd],Produced water reinjection pump.inlet_pressure_bar[bara],Produced water reinjection pump.outlet_pressure_bar[bara],Produced water reinjection pump.operational_head[J/kg],Base production load.is_valid[N/A],Base production load.energy_usage[MW (sd)],Base production load.energy_usage_cumulative[MWd (cd)],Base production load.power[MW (sd)],Base production load.power_cumulative[GWh (cd)],Flare.is_valid[N/A],Flare.energy_usage[Sm3/cd],Flare.energy_usage_cumulative[Sm3 (cd)],Flare.co2.rate[t/cd],Flare.co2.cumulative[t (cd)],Sea water injection pump.is_valid[N/A],Sea water injection pump.energy_usage[MW (sd)],Sea water injection pump.energy_usage_cumulative[MWd (cd)],Sea water injection pump.power[MW (sd)],Sea water injection pump.power_cumulative[GWh (cd)] 2020-01-01 00:00:00,1, 310830.00000, 0.00000, 27.71452, 0.00000, 680.71770, 0.00000, 12500.00000,nan,nan,54.45742,8.657777, 27.71452, 0.00000, 0.00000, 0.00000,1, 310830.00000, 0.00000, 27.71452, 0.00000, 680.71770, 0.00000, 12500.00000,nan,nan,54.45742,8.657777, 27.71452, 0.00000, 0.00000, 0.00000, 1.00000,1, 173830.00000, 0.00000, 27.71452, 0.00000, 380.68770, 0.00000, 72.28548,1, 130000.00000, 0.00000, 284.70000, 0.00000, 0.00000,0,1, 4.89000, 0.00000, 4.89000, 0.00000, 0.00000,0,1, 5.02452, 0.00000, 5.02452, 0.00000, 17000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 0.00000, 11.80000, 0.00000,1, 7000.00000, 0.00000, 15.33000, 0.00000,1, 6.00000, 0.00000, 6.00000, 0.00000 -2021-01-01 00:00:00,1, 311343.90000, 113763780.00000, 27.61307, 243.44430, 681.84320, 249142.70000, 11600.00000,54.45742,8.657777,58.77959,9.344926, 27.61307, 243.44430, 0.00000, 0.00000,1, 311343.90000, 113763780.00000, 27.61307, 243.44430, 681.84320, 249142.70000, 11600.00000,54.45742,8.657777,58.77959,9.344926, 27.61307, 243.44430, 0.00000, 0.00000, 1.00000,1, 173201.00000, 63621780.00000, 27.61307, 243.44430, 379.31020, 139331.70000, 72.38693,1, 131142.90000, 47580000.00000, 287.20300, 104200.20000, 0.00000,0,1, 5.01000, 1789.74000, 5.01000, 42.95376, 0.00000,0,1, 5.05307, 1838.97300, 5.05307, 44.13536, 17200.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 4318.80000, 11.80000, 103.65120,1, 7000.00000, 2562000.00000, 15.33000, 5610.78000,1, 5.75000, 2196.00000, 5.75000, 52.70400 -2022-01-01 00:00:00,1, 309378.10000, 227404304.00000, 27.11168, 485.33480, 677.53810, 498015.40000, 10700.00000,56.53484,8.988052,63.32132,10.06698, 27.11168, 485.33480, 0.00000, 0.00000,1, 309378.10000, 227404304.00000, 27.11168, 485.33480, 677.53810, 498015.40000, 10700.00000,56.53484,8.988052,63.32132,10.06698, 27.11168, 485.33480, 0.00000, 0.00000, 1.00000,1, 170092.40000, 126840145.00000, 27.11168, 485.33480, 372.50240, 277779.90000, 72.88832,1, 132285.70000, 95447158.00000, 289.70570, 209029.30000, 0.00000,0,1, 5.13000, 3618.39000, 5.13000, 86.84136, 0.00000,0,1, 4.68168, 3683.34500, 4.68168, 88.40027, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 8625.80000, 11.80000, 207.01920,1, 7000.00000, 5117000.00000, 15.33000, 11206.23000,1, 5.50000, 4294.75000, 5.50000, 103.07400 -2023-01-01 00:00:00,1, 317428.00000, 340327310.00000, 28.22570, 722.83320, 695.16730, 745316.90000, 9800.00000,58.61944,9.319466,70.93544,11.27749, 28.22570, 722.83320, 0.00000, 0.00000,1, 317428.00000, 340327310.00000, 28.22570, 722.83320, 695.16730, 745316.90000, 9800.00000,58.61944,9.319466,70.93544,11.27749, 28.22570, 722.83320, 0.00000, 0.00000, 1.00000,1, 176999.40000, 188923871.00000, 28.22570, 722.83320, 387.62870, 413743.30000, 71.77430,1, 133428.60000, 143731439.00000, 292.20860, 314771.90000, 0.00000,0,1, 5.56000, 5490.84000, 5.56000, 131.78020, 0.00000,0,1, 4.86570, 5392.15600, 4.86570, 129.41170, 16000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 12932.80000, 11.80000, 310.38720,1, 7000.00000, 7672000.00000, 15.33000, 16801.68000,1, 6.00000, 6302.25000, 6.00000, 151.25400 -2024-01-01 00:00:00,1, 341037.10000, 456188530.00000, 31.83370, 970.09030, 746.87130, 999052.90000, 9908.47000,61.32357,9.749375,75.37705,11.98363, 31.83370, 970.09030, 0.00000, 0.00000,1, 341037.10000, 456188530.00000, 31.83370, 970.09030, 746.87130, 999052.90000, 9908.47000,61.32357,9.749375,75.37705,11.98363, 31.83370, 970.09030, 0.00000, 0.00000, 1.00000,1, 199368.90000, 253528652.00000, 31.83370, 970.09030, 436.61790, 555227.80000, 68.16630,1, 134668.20000, 192432878.00000, 294.92340, 421428.00000, 0.00000,0,1, 5.75473, 7520.24000, 5.75473, 180.48580, 0.00000,0,1, 4.52221, 7168.13700, 4.52221, 172.03530, 14084.70000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 17239.80000, 11.80000, 413.75520,1, 7000.00000, 10227000.00000, 15.33000, 22397.13000,1, 9.75676, 8492.25000, 9.75676, 203.81400 -2025-01-01 00:00:00,1, 345398.60000, 581008109.00000, 32.36843, 1249.71800, 756.42290, 1272408.00000, 10000.00000,63.88231,10.15617,75.64229,12.0258, 32.36843, 1249.71800, 0.00000, 0.00000,1, 345398.60000, 581008109.00000, 32.36843, 1249.71800, 756.42290, 1272408.00000, 10000.00000,63.88231,10.15617,75.64229,12.0258, 32.36843, 1249.71800, 0.00000, 0.00000, 1.00000,1, 202684.30000, 326497669.00000, 32.36843, 1249.71800, 443.87860, 715029.90000, 67.63157,1, 135714.30000, 241721440.00000, 297.21430, 529370.00000, 0.00000,0,1, 6.13000, 9626.47000, 6.13000, 231.03530, 0.00000,0,1, 4.68168, 8823.26800, 4.68168, 211.75840, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 21558.60000, 11.80000, 517.40640,1, 7000.00000, 12789000.00000, 15.33000, 28007.91000,1, 9.75676, 12063.22000, 9.75676, 289.51740 -2026-01-01 00:00:00,1, 346729.90000, 707078598.00000, 32.39884, 1533.26500, 759.33840, 1548502.00000, 11100.00000,65.70359,10.44572,68.40886,10.87581, 32.39884, 1533.26500, 0.00000, 0.00000,1, 346729.90000, 707078598.00000, 32.39884, 1533.26500, 759.33840, 1548502.00000, 11100.00000,65.70359,10.44572,68.40886,10.87581, 32.39884, 1533.26500, 0.00000, 0.00000, 1.00000,1, 202872.80000, 400477438.00000, 32.39884, 1533.26500, 444.29140, 877045.60000, 67.60116,1, 136857.10000, 291257160.00000, 299.71700, 637853.20000, 0.00000,0,1, 6.25000, 11863.92000, 6.25000, 284.73410, 0.00000,0,1, 5.02452, 10532.08000, 5.02452, 252.76990, 17000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 25865.60000, 11.80000, 620.77440,1, 7000.00000, 15344000.00000, 15.33000, 33603.36000,1, 9.32432, 15624.44000, 9.32432, 374.98650 -2027-01-01 00:00:00,1, 355282.00000, 833635012.00000, 33.04086, 1817.07900, 778.06750, 1825661.00000, 10500.00000,66.10042,10.50881,74.10167,11.78087, 33.04086, 1817.07900, 0.00000, 0.00000,1, 355282.00000, 833635012.00000, 33.04086, 1817.07900, 778.06750, 1825661.00000, 10500.00000,66.10042,10.50881,74.10167,11.78087, 33.04086, 1817.07900, 0.00000, 0.00000, 1.00000,1, 206853.40000, 474526010.00000, 33.04086, 1817.07900, 453.00890, 1039212.00000, 66.95914,1, 141428.60000, 341210001.00000, 309.72860, 747249.90000, 0.00000,0,1, 6.37000, 14145.17000, 6.37000, 339.48410, 0.00000,0,1, 4.68168, 12366.03000, 4.68168, 296.78470, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 30172.60000, 11.80000, 724.14240,1, 7000.00000, 17899000.00000, 15.33000, 39198.81000,1, 10.18919, 19027.82000, 10.18919, 456.66760 -2028-01-01 00:00:00,1, 339026.40000, 963312942.00000, 32.26232, 2106.51700, 742.46780, 2109655.00000, 9500.00000,67.07539,10.66381,78.15451,12.4252, 32.26232, 2106.51700, 0.00000, 0.00000,1, 339026.40000, 963312942.00000, 32.26232, 2106.51700, 742.46780, 2109655.00000, 9500.00000,67.07539,10.66381,78.15451,12.4252, 32.26232, 2106.51700, 0.00000, 0.00000, 1.00000,1, 202026.40000, 550027501.00000, 32.26232, 2106.51700, 442.43780, 1204560.00000, 67.73768,1, 130000.00000, 392831440.00000, 284.70000, 860300.80000, 0.00000,0,1, 6.52000, 16470.22000, 6.52000, 395.28530, 0.00000,0,1, 4.18557, 14074.84000, 4.18557, 337.79620, 12000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 34479.60000, 11.80000, 827.51040,1, 7000.00000, 20454000.00000, 15.33000, 44794.26000,1, 9.75676, 22746.87000, 9.75676, 545.92490 -2029-01-01 00:00:00,1, 263106.70000, 1087396604.00000, 32.92043, 2389.90900, 576.20370, 2381399.00000, 7500.00000,68.17826,10.83915,76.82716,12.21417, 32.92043, 2389.90900, 0.00000, 0.00000,1, 263106.70000, 1087396604.00000, 32.92043, 2389.90900, 576.20370, 2381399.00000, 7500.00000,68.17826,10.83915,76.82716,12.21417, 32.92043, 2389.90900, 0.00000, 0.00000, 1.00000,1, 206106.70000, 623969164.00000, 32.92043, 2389.90900, 451.37370, 1366492.00000, 67.07957,1, 50000.00000, 440411440.00000, 109.50000, 964501.00000, 0.00000,0,1, 6.64000, 18856.54000, 6.64000, 452.55700, 0.00000,0,1, 4.50746, 15606.76000, 4.50746, 374.56220, 14000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 38798.40000, 11.80000, 931.16160,1, 7000.00000, 23016000.00000, 15.33000, 50405.04000,1, 9.97297, 26317.85000, 9.97297, 631.62830 -2030-01-01 00:00:00,1, 262298.20000, 1183430550.00000, 32.79003, 2678.29200, 574.43310, 2591713.00000, 8000.00000,68.80684,10.93908,71.80414,11.4156, 32.79003, 2678.29200, 0.00000, 0.00000,1, 262298.20000, 1183430550.00000, 32.79003, 2678.29200, 574.43310, 2591713.00000, 8000.00000,68.80684,10.93908,71.80414,11.4156, 32.79003, 2678.29200, 0.00000, 0.00000, 1.00000,1, 205298.20000, 699198109.00000, 32.79003, 2678.29200, 449.60310, 1531244.00000, 67.20997,1, 50000.00000, 458661440.00000, 109.50000, 1004469.00000, 0.00000,0,1, 6.80000, 21280.14000, 6.80000, 510.72340, 0.00000,0,1, 4.86570, 17251.98000, 4.86570, 414.04750, 16000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 43105.40000, 11.80000, 1034.53000,1, 7000.00000, 25571000.00000, 15.33000, 56000.49000,1, 9.32432, 29957.98000, 9.32432, 718.99150 -2031-01-01 00:00:00,1, 260635.10000, 1279169392.00000, 32.52178, 2965.53300, 570.79090, 2801381.00000, 7000.00000,69.02248,10.97337,81.54156,12.96368, 32.52178, 2965.53300, 0.00000, 0.00000,1, 260635.10000, 1279169392.00000, 32.52178, 2965.53300, 570.79090, 2801381.00000, 7000.00000,69.02248,10.97337,81.54156,12.96368, 32.52178, 2965.53300, 0.00000, 0.00000, 1.00000,1, 203635.10000, 774131952.00000, 32.52178, 2965.53300, 445.96090, 1695349.00000, 67.47822,1, 50000.00000, 476911440.00000, 109.50000, 1044436.00000, 0.00000,0,1, 6.89000, 23762.14000, 6.89000, 570.29140, 0.00000,0,1, 4.50746, 19027.96000, 4.50746, 456.67100, 14000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 47412.40000, 11.80000, 1137.89800,1, 7000.00000, 28126000.00000, 15.33000, 61595.94000,1, 9.32432, 33361.36000, 9.32432, 800.67260 +2021-01-01 00:00:00,1, 311343.90000, 113763780.00000, 27.61307, 243.44430, 681.84320, 249142.70000, 11600.00000,54.45742,8.657777,58.77959,9.344926, 27.61307, 243.44430, 0.00000, 0.00000,1, 311343.90000, 113763780.00000, 27.61307, 243.44430, 681.84320, 249142.70000, 11600.00000,54.45742,8.657777,58.77959,9.344926, 27.61307, 243.44430, 0.00000, 0.00000, 1.00000,1, 173201.00000, 63621780.00000, 27.61307, 243.44430, 379.31030, 139331.70000, 72.38693,1, 131142.90000, 47580000.00000, 287.20290, 104200.20000, 0.00000,0,1, 5.01000, 1789.74000, 5.01000, 42.95376, 0.00000,0,1, 5.05307, 1838.97300, 5.05307, 44.13536, 17200.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 4318.80000, 11.80000, 103.65120,1, 7000.00000, 2562000.00000, 15.33000, 5610.78000,1, 5.75000, 2196.00000, 5.75000, 52.70400 +2022-01-01 00:00:00,1, 309378.10000, 227404304.00000, 27.11168, 485.33480, 677.53800, 498015.40000, 10700.00000,56.53484,8.988052,63.32131,10.06698, 27.11168, 485.33480, 0.00000, 0.00000,1, 309378.10000, 227404304.00000, 27.11168, 485.33480, 677.53800, 498015.40000, 10700.00000,56.53484,8.988052,63.32131,10.06698, 27.11168, 485.33480, 0.00000, 0.00000, 1.00000,1, 170092.40000, 126840145.00000, 27.11168, 485.33480, 372.50230, 277780.00000, 72.88832,1, 132285.70000, 95447158.00000, 289.70570, 209029.30000, 0.00000,0,1, 5.13000, 3618.39000, 5.13000, 86.84136, 0.00000,0,1, 4.68168, 3683.34500, 4.68168, 88.40027, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 8625.80000, 11.80000, 207.01920,1, 7000.00000, 5117000.00000, 15.33000, 11206.23000,1, 5.50000, 4294.75000, 5.50000, 103.07400 +2023-01-01 00:00:00,1, 317428.00000, 340327310.00000, 28.22570, 722.83320, 695.16720, 745316.80000, 9800.00000,58.61944,9.319465,70.93543,11.27749, 28.22570, 722.83320, 0.00000, 0.00000,1, 317428.00000, 340327310.00000, 28.22570, 722.83320, 695.16720, 745316.80000, 9800.00000,58.61944,9.319465,70.93543,11.27749, 28.22570, 722.83320, 0.00000, 0.00000, 1.00000,1, 176999.40000, 188923871.00000, 28.22570, 722.83320, 387.62860, 413743.30000, 71.77430,1, 133428.60000, 143731439.00000, 292.20860, 314771.80000, 0.00000,0,1, 5.56000, 5490.84000, 5.56000, 131.78020, 0.00000,0,1, 4.86570, 5392.15600, 4.86570, 129.41170, 16000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 12932.80000, 11.80000, 310.38720,1, 7000.00000, 7672000.00000, 15.33000, 16801.68000,1, 6.00000, 6302.25000, 6.00000, 151.25400 +2024-01-01 00:00:00,1, 341037.10000, 456188530.00000, 31.83370, 970.09030, 746.87140, 999052.80000, 9908.47000,61.32356,9.749374,75.37706,11.98363, 31.83370, 970.09030, 0.00000, 0.00000,1, 341037.10000, 456188530.00000, 31.83370, 970.09030, 746.87140, 999052.80000, 9908.47000,61.32356,9.749374,75.37706,11.98363, 31.83370, 970.09030, 0.00000, 0.00000, 1.00000,1, 199368.90000, 253528652.00000, 31.83370, 970.09030, 436.61800, 555227.70000, 68.16630,1, 134668.20000, 192432878.00000, 294.92340, 421428.00000, 0.00000,0,1, 5.75473, 7520.24000, 5.75473, 180.48580, 0.00000,0,1, 4.52221, 7168.13700, 4.52221, 172.03530, 14084.70000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 17239.80000, 11.80000, 413.75520,1, 7000.00000, 10227000.00000, 15.33000, 22397.13000,1, 9.75676, 8492.25000, 9.75676, 203.81400 +2025-01-01 00:00:00,1, 345398.60000, 581008109.00000, 32.36843, 1249.71800, 756.42290, 1272408.00000, 10000.00000,63.88231,10.15617,75.64229,12.0258, 32.36843, 1249.71800, 0.00000, 0.00000,1, 345398.60000, 581008109.00000, 32.36843, 1249.71800, 756.42290, 1272408.00000, 10000.00000,63.88231,10.15617,75.64229,12.0258, 32.36843, 1249.71800, 0.00000, 0.00000, 1.00000,1, 202684.30000, 326497669.00000, 32.36843, 1249.71800, 443.87860, 715029.90000, 67.63157,1, 135714.30000, 241721440.00000, 297.21430, 529369.90000, 0.00000,0,1, 6.13000, 9626.47000, 6.13000, 231.03530, 0.00000,0,1, 4.68168, 8823.26800, 4.68168, 211.75840, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 21558.60000, 11.80000, 517.40640,1, 7000.00000, 12789000.00000, 15.33000, 28007.91000,1, 9.75676, 12063.22000, 9.75676, 289.51740 +2026-01-01 00:00:00,1, 346729.90000, 707078598.00000, 32.39884, 1533.26500, 759.33860, 1548502.00000, 11100.00000,65.70359,10.44572,68.40888,10.87582, 32.39884, 1533.26500, 0.00000, 0.00000,1, 346729.90000, 707078598.00000, 32.39884, 1533.26500, 759.33860, 1548502.00000, 11100.00000,65.70359,10.44572,68.40888,10.87582, 32.39884, 1533.26500, 0.00000, 0.00000, 1.00000,1, 202872.80000, 400477438.00000, 32.39884, 1533.26500, 444.29150, 877045.60000, 67.60116,1, 136857.10000, 291257160.00000, 299.71710, 637853.20000, 0.00000,0,1, 6.25000, 11863.92000, 6.25000, 284.73410, 0.00000,0,1, 5.02452, 10532.08000, 5.02452, 252.76990, 17000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 25865.60000, 11.80000, 620.77440,1, 7000.00000, 15344000.00000, 15.33000, 33603.36000,1, 9.32432, 15624.44000, 9.32432, 374.98650 +2027-01-01 00:00:00,1, 355282.00000, 833635012.00000, 33.04086, 1817.07900, 778.06750, 1825661.00000, 10500.00000,66.10043,10.50881,74.10167,11.78087, 33.04086, 1817.07900, 0.00000, 0.00000,1, 355282.00000, 833635012.00000, 33.04086, 1817.07900, 778.06750, 1825661.00000, 10500.00000,66.10043,10.50881,74.10167,11.78087, 33.04086, 1817.07900, 0.00000, 0.00000, 1.00000,1, 206853.40000, 474526010.00000, 33.04086, 1817.07900, 453.00890, 1039212.00000, 66.95914,1, 141428.60000, 341210001.00000, 309.72860, 747249.90000, 0.00000,0,1, 6.37000, 14145.17000, 6.37000, 339.48410, 0.00000,0,1, 4.68168, 12366.03000, 4.68168, 296.78470, 15000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 30172.60000, 11.80000, 724.14240,1, 7000.00000, 17899000.00000, 15.33000, 39198.81000,1, 10.18919, 19027.82000, 10.18919, 456.66760 +2028-01-01 00:00:00,1, 339026.40000, 963312942.00000, 32.26232, 2106.51700, 742.46780, 2109655.00000, 9500.00000,67.0754,10.66381,78.15451,12.4252, 32.26232, 2106.51700, 0.00000, 0.00000,1, 339026.40000, 963312942.00000, 32.26232, 2106.51700, 742.46780, 2109655.00000, 9500.00000,67.0754,10.66381,78.15451,12.4252, 32.26232, 2106.51700, 0.00000, 0.00000, 1.00000,1, 202026.40000, 550027501.00000, 32.26232, 2106.51700, 442.43780, 1204560.00000, 67.73768,1, 130000.00000, 392831440.00000, 284.70000, 860300.80000, 0.00000,0,1, 6.52000, 16470.22000, 6.52000, 395.28530, 0.00000,0,1, 4.18557, 14074.84000, 4.18557, 337.79620, 12000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 34479.60000, 11.80000, 827.51040,1, 7000.00000, 20454000.00000, 15.33000, 44794.26000,1, 9.75676, 22746.87000, 9.75676, 545.92490 +2029-01-01 00:00:00,1, 263106.70000, 1087396604.00000, 32.92043, 2389.90900, 576.20360, 2381399.00000, 7500.00000,68.17826,10.83915,76.82715,12.21417, 32.92043, 2389.90900, 0.00000, 0.00000,1, 263106.70000, 1087396604.00000, 32.92043, 2389.90900, 576.20360, 2381399.00000, 7500.00000,68.17826,10.83915,76.82715,12.21417, 32.92043, 2389.90900, 0.00000, 0.00000, 1.00000,1, 206106.70000, 623969164.00000, 32.92043, 2389.90900, 451.37360, 1366492.00000, 67.07957,1, 50000.00000, 440411440.00000, 109.50000, 964501.00000, 0.00000,0,1, 6.64000, 18856.54000, 6.64000, 452.55700, 0.00000,0,1, 4.50746, 15606.76000, 4.50746, 374.56220, 14000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 38798.40000, 11.80000, 931.16160,1, 7000.00000, 23016000.00000, 15.33000, 50405.04000,1, 9.97297, 26317.85000, 9.97297, 631.62830 +2030-01-01 00:00:00,1, 262298.20000, 1183430550.00000, 32.79003, 2678.29200, 574.43300, 2591713.00000, 8000.00000,68.80684,10.93908,71.80412,11.4156, 32.79003, 2678.29200, 0.00000, 0.00000,1, 262298.20000, 1183430550.00000, 32.79003, 2678.29200, 574.43300, 2591713.00000, 8000.00000,68.80684,10.93908,71.80412,11.4156, 32.79003, 2678.29200, 0.00000, 0.00000, 1.00000,1, 205298.20000, 699198109.00000, 32.79003, 2678.29200, 449.60300, 1531244.00000, 67.20997,1, 50000.00000, 458661440.00000, 109.50000, 1004469.00000, 0.00000,0,1, 6.80000, 21280.14000, 6.80000, 510.72340, 0.00000,0,1, 4.86570, 17251.98000, 4.86570, 414.04750, 16000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 43105.40000, 11.80000, 1034.53000,1, 7000.00000, 25571000.00000, 15.33000, 56000.49000,1, 9.32432, 29957.98000, 9.32432, 718.99150 +2031-01-01 00:00:00,1, 260635.10000, 1279169392.00000, 32.52178, 2965.53300, 570.79080, 2801381.00000, 7000.00000,69.02248,10.97337,81.54154,12.96368, 32.52178, 2965.53300, 0.00000, 0.00000,1, 260635.10000, 1279169392.00000, 32.52178, 2965.53300, 570.79080, 2801381.00000, 7000.00000,69.02248,10.97337,81.54154,12.96368, 32.52178, 2965.53300, 0.00000, 0.00000, 1.00000,1, 203635.10000, 774131952.00000, 32.52178, 2965.53300, 445.96080, 1695349.00000, 67.47822,1, 50000.00000, 476911440.00000, 109.50000, 1044436.00000, 0.00000,0,1, 6.89000, 23762.14000, 6.89000, 570.29140, 0.00000,0,1, 4.50746, 19027.96000, 4.50746, 456.67100, 14000.00000, 10.00000, 200.00000, 18811.88000,1, 11.80000, 47412.40000, 11.80000, 1137.89800,1, 7000.00000, 28126000.00000, 15.33000, 61595.94000,1, 9.32432, 33361.36000, 9.32432, 800.67260 2032-01-01 00:00:00,1, 0.00000, 1374301204.00000, 0.00000, 3250.42300, 0.00000, 3009720.00000, 0.00000,69.76391,11.09124,nan,nan, 0.00000, 3250.42300, 0.00000, 0.00000,1, 0.00000, 1374301204.00000, 0.00000, 3250.42300, 0.00000, 3009720.00000, 0.00000,69.76391,11.09124,nan,nan, 0.00000, 3250.42300, 0.00000, 0.00000, 1.00000,1, 0.00000, 848458764.00000, 0.00000, 3250.42300, 0.00000, 1858125.00000, 0.00000,1, 0.00000, 495161440.00000, 0.00000, 1084404.00000, 0.00000,0,1, 0.00000, 26276.99000, 0.00000, 630.64780, 0.00000,0,1, 0.00000, 20673.18000, 0.00000, 496.15640, 0.00000, 10.00000, 200.00000, 18811.88000,1, 0.00000, 51719.40000, 0.00000, 1241.26600,1, 0.00000, 30681000.00000, 0.00000, 67191.39000,1, 0.00000, 36764.74000, 0.00000, 882.35370 diff --git a/src/tests/ecalc_cli/snapshots/test_app/test_json_advanced_model/test_json_advanced_model_v3.json b/src/tests/ecalc_cli/snapshots/test_app/test_json_advanced_model/test_json_advanced_model_v3.json index 253557126a..6d9da24136 100644 --- a/src/tests/ecalc_cli/snapshots/test_app/test_json_advanced_model/test_json_advanced_model_v3.json +++ b/src/tests/ecalc_cli/snapshots/test_app/test_json_advanced_model/test_json_advanced_model_v3.json @@ -281,7 +281,7 @@ 17.80075, 16.4695, 15.32428, - 14.93148, + 14.93149, 14.65856, 13.99612, 12.93783, @@ -341,7 +341,7 @@ 80.88581, 81.23225, 84.27068, - 87.96581, + 87.96582, 91.58344, 95.57426, 99.53709, @@ -389,7 +389,7 @@ 13.08401, 13.10623, 9.765231, - 7.07478, + 7.074779, 11.96209, 13.69574, 28.999, @@ -437,13 +437,13 @@ 130.9593, 100.738, 85.44467, - 74.99065, + 74.99066, 67.92914, 82.29842, 82.43817, 61.4233, 44.50036, - 75.24153, + 75.24154, 86.14621, 182.4037, 272.5222, @@ -766,9 +766,9 @@ 1648.763, 1289.889, 1246.01, - 1203.864, + 1203.865, 1206.047, - 1203.864, + 1203.865, 1199.098, 1195.583, 1195.583, @@ -25672,7 +25672,7 @@ 17.91261, 18.65345, 19.37784, - 20.18235, + 20.18236, 20.98201, 21.78115, 22.63859, @@ -25771,10 +25771,10 @@ 19.11016, 19.15459, 12.80869, - 9.278569, + 9.278568, 15.39994, 17.6495, - 37.33319, + 37.3332, 55.65533, 58.0395, 81.25529, @@ -25819,13 +25819,13 @@ 173.1308, 133.1775, 111.6974, - 97.75314, + 97.75315, 89.12781, 120.2029, 120.4824, 80.56666, - 58.3622, - 96.86564, + 58.36219, + 96.86565, 111.0154, 234.8258, 350.072, @@ -26070,13 +26070,13 @@ 3370466.0, 3668696.0, 3951544.0, - 4235965.0, + 4235966.0, 4518813.0, 4799921.0, 5079746.0, - 5360337.0, - 5640162.0, - 5919987.0, + 5360338.0, + 5640163.0, + 5919988.0, 6199812.0, 6480404.0 ] @@ -26142,16 +26142,16 @@ 865.654, 865.654, 837.7307, - 830.9017, + 830.9018, 846.7142, 1202.029, 1204.824, 845.9499, - 817.0708, - 774.9251, - 777.1075, - 774.9251, - 770.1584, + 817.0707, + 774.9252, + 777.1076, + 774.9252, + 770.1585, 766.6437, 766.6437, 766.6437, @@ -28689,7 +28689,7 @@ 4192632.0, 4473874.0, 4753376.0, - 5031594.0, + 5031595.0, 5310576.0, 5588795.0, 5867014.0, @@ -28758,16 +28758,16 @@ 854.654, 854.654, 826.7307, - 819.9017, + 819.9018, 835.7142, 1191.029, 1193.824, 834.9499, - 812.6708, - 770.5251, - 772.7075, - 770.5251, - 765.7584, + 812.6707, + 770.5252, + 772.7076, + 770.5252, + 765.7585, 762.2437, 762.2437, 762.2437, diff --git a/src/tests/ecalc_cli/snapshots/test_app/test_json_true/test_v3.json b/src/tests/ecalc_cli/snapshots/test_app/test_json_true/test_v3.json index ce075db0f6..9c23c939ea 100644 --- a/src/tests/ecalc_cli/snapshots/test_app/test_json_true/test_v3.json +++ b/src/tests/ecalc_cli/snapshots/test_app/test_json_true/test_v3.json @@ -24,8 +24,8 @@ null, 8.657777, 8.988052, - 9.319466, - 9.749375, + 9.319465, + 9.749374, 10.12661, 10.44572, 10.50881, @@ -56,11 +56,11 @@ 54.45742, 56.53484, 58.61944, - 61.32357, + 61.32356, 63.69638, 65.70359, - 66.10042, - 67.07539, + 66.10043, + 67.0754, 68.17826, 68.80684, 69.02248 @@ -89,7 +89,7 @@ 11.27749, 11.98363, 11.98363, - 10.87581, + 10.87582, 11.78087, 12.4252, 12.21417, @@ -116,15 +116,15 @@ "values": [ 54.45742, 58.77959, - 63.32132, - 70.93544, - 75.37705, - 75.37705, - 68.40886, + 63.32131, + 70.93543, + 75.37706, + 75.37706, + 68.40888, 74.10167, 78.15451, - 76.82716, - 71.80414, + 76.82715, + 71.80412, null ] }, @@ -167,8 +167,8 @@ 0.0, 249142.7, 498015.4, - 745316.9, - 999052.9, + 745316.8, + 999052.8, 1248959.0, 1548502.0, 1825661.0, @@ -213,16 +213,16 @@ "values": [ 680.7177, 681.8432, - 677.5381, - 695.1673, - 745.9874, + 677.538, + 695.1672, + 745.9875, 756.4229, - 759.3384, + 759.3386, 778.0675, 742.4678, - 576.2037, - 574.4331, - 570.7909 + 576.2036, + 574.433, + 570.7908 ] }, "timesteps": [ @@ -5922,8 +5922,8 @@ null, 8.657777, 8.988052, - 9.319466, - 9.749375, + 9.319465, + 9.749374, 10.12661, 10.44572, 10.50881, @@ -5954,11 +5954,11 @@ 54.45742, 56.53484, 58.61944, - 61.32357, + 61.32356, 63.69638, 65.70359, - 66.10042, - 67.07539, + 66.10043, + 67.0754, 68.17826, 68.80684, 69.02248 @@ -5987,7 +5987,7 @@ 11.27749, 11.98363, 11.98363, - 10.87581, + 10.87582, 11.78087, 12.4252, 12.21417, @@ -6014,15 +6014,15 @@ "values": [ 54.45742, 58.77959, - 63.32132, - 70.93544, - 75.37705, - 75.37705, - 68.40886, + 63.32131, + 70.93543, + 75.37706, + 75.37706, + 68.40888, 74.10167, 78.15451, - 76.82716, - 71.80414, + 76.82715, + 71.80412, null ] }, @@ -6065,8 +6065,8 @@ 0.0, 249142.7, 498015.4, - 745316.9, - 999052.9, + 745316.8, + 999052.8, 1248959.0, 1548502.0, 1825661.0, @@ -6111,16 +6111,16 @@ "values": [ 680.7177, 681.8432, - 677.5381, - 695.1673, - 745.9874, + 677.538, + 695.1672, + 745.9875, 756.4229, - 759.3384, + 759.3386, 778.0675, 742.4678, - 576.2037, - 574.4331, - 570.7909 + 576.2036, + 574.433, + 570.7908 ] }, "timesteps": [ @@ -6597,9 +6597,9 @@ "values": [ 0.0, 139331.7, - 277779.9, + 277780.0, 413743.3, - 555227.8, + 555227.7, 701269.7, 877045.6, 1039212.0, @@ -6643,17 +6643,17 @@ "unit": "t/d", "values": [ 380.6877, - 379.3102, - 372.5024, - 387.6287, - 435.946, + 379.3103, + 372.5023, + 387.6286, + 435.9461, 443.8786, - 444.2914, + 444.2915, 453.0089, 442.4378, - 451.3737, - 449.6031, - 445.9609 + 451.3736, + 449.603, + 445.9608 ] }, "timesteps": [ @@ -6946,7 +6946,7 @@ 0.0, 104200.2, 209029.3, - 314771.9, + 314771.8, 421428.0, 520156.3, 637853.2, @@ -6991,12 +6991,12 @@ "unit": "t/d", "values": [ 284.7, - 287.203, + 287.2029, 289.7057, 292.2086, 294.7114, 297.2143, - 299.717, + 299.7171, 309.7286, 284.7, 109.5, diff --git a/src/tests/ecalc_cli/snapshots/test_app/test_json_true_detailed_output/test_full_json_v3.json b/src/tests/ecalc_cli/snapshots/test_app/test_json_true_detailed_output/test_full_json_v3.json index ce075db0f6..9c23c939ea 100644 --- a/src/tests/ecalc_cli/snapshots/test_app/test_json_true_detailed_output/test_full_json_v3.json +++ b/src/tests/ecalc_cli/snapshots/test_app/test_json_true_detailed_output/test_full_json_v3.json @@ -24,8 +24,8 @@ null, 8.657777, 8.988052, - 9.319466, - 9.749375, + 9.319465, + 9.749374, 10.12661, 10.44572, 10.50881, @@ -56,11 +56,11 @@ 54.45742, 56.53484, 58.61944, - 61.32357, + 61.32356, 63.69638, 65.70359, - 66.10042, - 67.07539, + 66.10043, + 67.0754, 68.17826, 68.80684, 69.02248 @@ -89,7 +89,7 @@ 11.27749, 11.98363, 11.98363, - 10.87581, + 10.87582, 11.78087, 12.4252, 12.21417, @@ -116,15 +116,15 @@ "values": [ 54.45742, 58.77959, - 63.32132, - 70.93544, - 75.37705, - 75.37705, - 68.40886, + 63.32131, + 70.93543, + 75.37706, + 75.37706, + 68.40888, 74.10167, 78.15451, - 76.82716, - 71.80414, + 76.82715, + 71.80412, null ] }, @@ -167,8 +167,8 @@ 0.0, 249142.7, 498015.4, - 745316.9, - 999052.9, + 745316.8, + 999052.8, 1248959.0, 1548502.0, 1825661.0, @@ -213,16 +213,16 @@ "values": [ 680.7177, 681.8432, - 677.5381, - 695.1673, - 745.9874, + 677.538, + 695.1672, + 745.9875, 756.4229, - 759.3384, + 759.3386, 778.0675, 742.4678, - 576.2037, - 574.4331, - 570.7909 + 576.2036, + 574.433, + 570.7908 ] }, "timesteps": [ @@ -5922,8 +5922,8 @@ null, 8.657777, 8.988052, - 9.319466, - 9.749375, + 9.319465, + 9.749374, 10.12661, 10.44572, 10.50881, @@ -5954,11 +5954,11 @@ 54.45742, 56.53484, 58.61944, - 61.32357, + 61.32356, 63.69638, 65.70359, - 66.10042, - 67.07539, + 66.10043, + 67.0754, 68.17826, 68.80684, 69.02248 @@ -5987,7 +5987,7 @@ 11.27749, 11.98363, 11.98363, - 10.87581, + 10.87582, 11.78087, 12.4252, 12.21417, @@ -6014,15 +6014,15 @@ "values": [ 54.45742, 58.77959, - 63.32132, - 70.93544, - 75.37705, - 75.37705, - 68.40886, + 63.32131, + 70.93543, + 75.37706, + 75.37706, + 68.40888, 74.10167, 78.15451, - 76.82716, - 71.80414, + 76.82715, + 71.80412, null ] }, @@ -6065,8 +6065,8 @@ 0.0, 249142.7, 498015.4, - 745316.9, - 999052.9, + 745316.8, + 999052.8, 1248959.0, 1548502.0, 1825661.0, @@ -6111,16 +6111,16 @@ "values": [ 680.7177, 681.8432, - 677.5381, - 695.1673, - 745.9874, + 677.538, + 695.1672, + 745.9875, 756.4229, - 759.3384, + 759.3386, 778.0675, 742.4678, - 576.2037, - 574.4331, - 570.7909 + 576.2036, + 574.433, + 570.7908 ] }, "timesteps": [ @@ -6597,9 +6597,9 @@ "values": [ 0.0, 139331.7, - 277779.9, + 277780.0, 413743.3, - 555227.8, + 555227.7, 701269.7, 877045.6, 1039212.0, @@ -6643,17 +6643,17 @@ "unit": "t/d", "values": [ 380.6877, - 379.3102, - 372.5024, - 387.6287, - 435.946, + 379.3103, + 372.5023, + 387.6286, + 435.9461, 443.8786, - 444.2914, + 444.2915, 453.0089, 442.4378, - 451.3737, - 449.6031, - 445.9609 + 451.3736, + 449.603, + 445.9608 ] }, "timesteps": [ @@ -6946,7 +6946,7 @@ 0.0, 104200.2, 209029.3, - 314771.9, + 314771.8, 421428.0, 520156.3, 637853.2, @@ -6991,12 +6991,12 @@ "unit": "t/d", "values": [ 284.7, - 287.203, + 287.2029, 289.7057, 292.2086, 294.7114, 297.2143, - 299.717, + 299.7171, 309.7286, 284.7, 109.5, diff --git a/src/tests/libecalc/dto/test_categories.py b/src/tests/libecalc/dto/test_categories.py index eb37942290..71a05e8374 100644 --- a/src/tests/libecalc/dto/test_categories.py +++ b/src/tests/libecalc/dto/test_categories.py @@ -15,6 +15,7 @@ InstallationUserDefinedCategoryType, ) from libecalc.expression import Expression +from libecalc.presentation.yaml.yaml_types.components.yaml_installation import YamlInstallation from libecalc.presentation.yaml.yaml_types.emitters.yaml_venting_emitter import ( YamlDirectTypeEmitter, YamlVentingEmission, @@ -174,9 +175,9 @@ def test_installation_categories(self, flare): # Check that lower case raises error with pytest.raises(ValidationError) as exc_info: - dto.components.Installation( + YamlInstallation( name="test", - user_defined_category="fixed", + category="fixed", hydrocarbon_export={datetime(1900, 1, 1): Expression.setup_from_expression(0)}, regularity={datetime(1900, 1, 1): Expression.setup_from_expression(1)}, ) diff --git a/src/tests/libecalc/input/mappers/test_resolve_fuel.py b/src/tests/libecalc/input/mappers/test_resolve_fuel.py index ea48ea4689..99b83973de 100644 --- a/src/tests/libecalc/input/mappers/test_resolve_fuel.py +++ b/src/tests/libecalc/input/mappers/test_resolve_fuel.py @@ -1,13 +1,12 @@ from datetime import datetime import pytest +from inline_snapshot import snapshot import libecalc.dto.fuel_type -from libecalc.common.errors.exceptions import InvalidReferenceException from libecalc.common.time_utils import Period +from libecalc.presentation.yaml.domain.reference_service import InvalidReferenceException from libecalc.presentation.yaml.mappers.component_mapper import _resolve_fuel - -# from libecalc.presentation.yaml.mappers import _resolve_fuel from libecalc.presentation.yaml.yaml_entities import References @@ -45,12 +44,16 @@ def test_consumer_fuel(self, references, all_the_time): def test_both(self, references, all_the_time): assert _resolve_fuel("diesel", "fuel_gas", references, target_period=all_the_time).popitem()[1].name == "diesel" + @pytest.mark.snapshot + @pytest.mark.inlinesnapshot def test_invalid(self, references, all_the_time): with pytest.raises(InvalidReferenceException) as exc_info: assert ( _resolve_fuel("diessel", "fuel_gass", references, target_period=all_the_time).popitem()[1] == "diessel" ) - assert "Invalid reference: 'diessel' not found." in str(exc_info.value) + assert str(exc_info.value) == snapshot( + "Invalid fuel reference 'diessel'. Available references: fuel_gas, diesel" + ) def test_resolve_multiple_fuels(self, references, all_the_time): _resolve_fuel( diff --git a/src/tests/libecalc/integration/test_multiple_installations.py b/src/tests/libecalc/integration/test_multiple_installations.py index 70eb6d7a36..b9831051aa 100644 --- a/src/tests/libecalc/integration/test_multiple_installations.py +++ b/src/tests/libecalc/integration/test_multiple_installations.py @@ -30,8 +30,8 @@ def test_asset_with_multiple_installations(asset_with_two_installations): energy_calculator = EnergyCalculator(graph) timesteps = [datetime(2020, 1, 1), datetime(2021, 1, 1), datetime(2022, 1, 1)] variables_map = VariablesMap(time_vector=timesteps) - consumer_results = energy_calculator.evaluate_energy_usage(variables_map) - emission_results = energy_calculator.evaluate_emissions(variables_map, consumer_results) + consumer_results = energy_calculator.evaluate_energy_usage() + emission_results = energy_calculator.evaluate_emissions() graph_result = GraphResult( graph=graph, variables_map=variables_map, diff --git a/src/tests/libecalc/presentation/exporter/test_ltp.py b/src/tests/libecalc/presentation/exporter/test_ltp.py index 5106454dfa..c51c47cebb 100644 --- a/src/tests/libecalc/presentation/exporter/test_ltp.py +++ b/src/tests/libecalc/presentation/exporter/test_ltp.py @@ -1,6 +1,5 @@ from datetime import datetime from pathlib import Path -from typing import Union import pandas as pd import pytest @@ -50,7 +49,8 @@ ) from libecalc.presentation.json_result.mapper import get_asset_result from libecalc.presentation.json_result.result import EcalcModelResult -from libecalc.presentation.yaml.validation_errors import DtoValidationError +from libecalc.presentation.yaml.model import YamlModel +from libecalc.presentation.yaml.model_validation_exception import ModelValidationException from libecalc.presentation.yaml.yaml_keywords import EcalcYamlKeywords from libecalc.presentation.yaml.yaml_types.yaml_stream_conditions import ( YamlEmissionRateUnits, @@ -68,15 +68,14 @@ def calculate_asset_result( - model: Union[dto.Installation, dto.Asset], + model: YamlModel, variables: VariablesMap, ): - model = model graph = model.get_graph() energy_calculator = EnergyCalculator(graph=graph) - consumer_results = energy_calculator.evaluate_energy_usage(variables) - emission_results = energy_calculator.evaluate_emissions(variables, consumer_results) + consumer_results = energy_calculator.evaluate_energy_usage() + emission_results = energy_calculator.evaluate_emissions() results_core = GraphResult( graph=graph, @@ -328,7 +327,7 @@ def test_only_venting_emitters_no_fuelconsumers(): variables = VariablesMap(time_vector=time_vector, variables={}) # Installation with only venting emitters: - dto_case_emitters = venting_emitter_yaml_factory( + ecalc_model_emitters = venting_emitter_yaml_factory( emission_rates=[emission_rate], regularity=regularity, units=[YamlEmissionRateUnits.KILO_PER_DAY], @@ -342,21 +341,19 @@ def test_only_venting_emitters_no_fuelconsumers(): ) venting_emitter_results = get_consumption( - model=dto_case_emitters.ecalc_model, variables=variables, time_vector=time_vector_yearly + model=ecalc_model_emitters, variables=variables, time_vector=time_vector_yearly ) # Verify that eCalc is not failing in get_asset_result with only venting emitters - # when installation result is empty, i.e. with no genset and fuel consumers: - assert isinstance( - calculate_asset_result(model=dto_case_emitters.ecalc_model, variables=variables), EcalcModelResult - ) + assert isinstance(calculate_asset_result(model=ecalc_model_emitters, variables=variables), EcalcModelResult) # Verify correct emissions: emissions_ch4 = get_sum_ltp_column(venting_emitter_results, installation_nr=0, ltp_column_nr=0) assert emissions_ch4 == (emission_rate / 1000) * 365 * regularity # Installation with only fuel consumers: - dto_case_fuel = venting_emitter_yaml_factory( + ecalc_model_fuel = venting_emitter_yaml_factory( emission_rates=[emission_rate], regularity=regularity, units=[YamlEmissionRateUnits.KILO_PER_DAY], @@ -371,7 +368,7 @@ def test_only_venting_emitters_no_fuelconsumers(): asset_multi_installations = dto.Asset( name="Multi installations", - installations=[dto_case_emitters.ecalc_model.installations[0], dto_case_fuel.ecalc_model.installations[0]], + installations=[ecalc_model_fuel.installations[0], ecalc_model_fuel.installations[0]], ) # Verify that eCalc is not failing in get_asset_result, with only venting emitters - @@ -399,7 +396,7 @@ def test_no_emitters_or_fuelconsumers(): regularity = 0.2 emission_rate = 10 - with pytest.raises(DtoValidationError) as ee: + with pytest.raises(ModelValidationException) as ee: venting_emitter_yaml_factory( emission_rates=[emission_rate], regularity=regularity, @@ -412,7 +409,7 @@ def test_no_emitters_or_fuelconsumers(): path=Path(venting_emitters.__path__[0]), ) - error_message = ee.value.extended_message + error_message = str(ee.value) assert "minimal_installation" in error_message assert f"It is required to specify at least one of the keywords {EcalcYamlKeywords.fuel_consumers}, {EcalcYamlKeywords.generator_sets} or {EcalcYamlKeywords.installation_venting_emitters} in the model."