Coverage for agentlib_flexquant/data_structures/mpcs.py: 100%
67 statements
« prev ^ index » next coverage.py v7.4.4, created at 2025-10-20 14:09 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2025-10-20 14:09 +0000
1"""
2Data models for MPC configurations in flexibility quantification.
4This module defines Pydantic data models that encapsulate configuration parameters
5for baseline, positive flexibility, and negative flexibility MPC controllers used
6in flexquant. The models handle file paths, module configurations, variable
7mappings, and optimization weights for MPC implementations.
8"""
9import pydantic
10from agentlib_mpc.data_structures.mpc_datamodels import MPCVariable
11from pydantic import ConfigDict, model_validator
13import agentlib_flexquant.data_structures.globals as glbs
14import agentlib_flexquant.utils.config_management as cmng
17class BaseMPCData(pydantic.BaseModel):
18 """Base class containing necessary data for the code creation of the different mpcs"""
20 # files and paths
21 created_flex_mpcs_file: str = "flex_agents.py"
22 name_of_created_file: str
23 results_suffix: str
24 # modules
25 module_types: dict
26 class_name: str
27 module_id: str
28 # variables
29 power_alias: str
30 stored_energy_alias: str
31 config_inputs_appendix: list[MPCVariable] = []
32 config_parameters_appendix: list[MPCVariable] = []
33 weights: list[MPCVariable] = pydantic.Field(
34 default=[], description="Name and value of weights",
35 )
36 model_config = ConfigDict(json_encoders={MPCVariable: lambda v: v.dict()})
39class BaselineMPCData(BaseMPCData):
40 """Data class for Baseline MPC"""
42 # files and paths
43 results_suffix: str = "_base.csv"
44 name_of_created_file: str = "baseline.json"
45 # modules
46 module_types: dict = cmng.BASELINE_MODULE_TYPE_DICT
47 class_name: str = "BaselineMPCModel"
48 module_id: str = "Baseline"
49 # variables
50 power_alias: str = glbs.POWER_ALIAS_BASE
51 stored_energy_alias: str = glbs.STORED_ENERGY_ALIAS_BASE
52 power_variable: str = pydantic.Field(
53 default="P_el",
54 description=(
55 "Name of the variable representing the electrical power in the baseline config"
56 ),
57 )
58 profile_deviation_weight: float = pydantic.Field(
59 default=0,
60 description="Weight of soft constraint for deviation from accepted flexible profile",
61 )
62 power_unit: str = pydantic.Field(
63 default="kW", description="Unit of the power variable"
64 )
65 comfort_variable: str = pydantic.Field(
66 default=None,
67 description=(
68 "Name of the slack variable representing the thermal comfort in the baseline config"
69 ),
70 )
71 profile_comfort_weight: float = pydantic.Field(
72 default=1, description="Weight of soft constraint for discomfort",
73 )
74 config_inputs_appendix: list[MPCVariable] = [
75 MPCVariable(name="_P_external", value=0, unit="W"),
76 MPCVariable(name="in_provision", value=False),
77 MPCVariable(name="rel_start", value=0, unit="s"),
78 MPCVariable(name="rel_end", value=0, unit="s"),
79 ]
81 config_parameters_appendix: list[MPCVariable] = []
83 weights: list[MPCVariable] = pydantic.Field(
84 default=[], description="Name and value of weights",
85 )
86 model_config = ConfigDict(json_encoders={MPCVariable: lambda v: v.dict()})
88 @model_validator(mode="after")
89 def update_config_parameters_appendix(self) -> "BaselineMPCData":
90 """Update the config parameters appendix with profile deviation and comfort weights.
92 Adds the profile deviation weight parameter and optionally the profile comfort
93 weight parameter (if comfort_variable is enabled) to the config_parameters_appendix
94 list as MPCVariable instances.
95 """
96 self.config_parameters_appendix = [
97 MPCVariable(
98 name=glbs.PROFILE_DEVIATION_WEIGHT,
99 value=self.profile_deviation_weight,
100 unit="-",
101 description=(
102 "Weight of soft constraint for deviation from accepted flexible profile"
103 ),
104 )
105 ]
106 if self.comfort_variable:
107 self.config_parameters_appendix.append(
108 MPCVariable(
109 name=glbs.PROFILE_COMFORT_WEIGHT,
110 value=self.profile_comfort_weight,
111 unit="-",
112 description="Weight of soft constraint for discomfort",
113 )
114 )
115 return self
118class PFMPCData(BaseMPCData):
119 """Data class for PF-MPC"""
121 # files and paths
122 results_suffix: str = "_pos_flex.csv"
123 name_of_created_file: str = "pos_flex.json"
124 # modules
125 module_types: dict = cmng.SHADOW_MODULE_TYPE_DICT
126 class_name: str = "PosFlexModel"
127 module_id: str = "PosFlexMPC"
128 # variables
129 power_alias: str = glbs.POWER_ALIAS_POS
130 stored_energy_alias: str = glbs.STORED_ENERGY_ALIAS_POS
131 flex_cost_function: str = pydantic.Field(
132 default=None, description="Cost function of the PF-MPC",
133 )
134 # initialize market parameters with dummy values (0)
135 config_parameters_appendix: list[MPCVariable] = [
136 MPCVariable(name=glbs.PREP_TIME, value=0, unit="s"),
137 MPCVariable(name=glbs.MARKET_TIME, value=0, unit="s"),
138 MPCVariable(name=glbs.FLEX_EVENT_DURATION, value=0, unit="s")
139 ]
140 config_inputs_appendix: list[MPCVariable] = [
141 MPCVariable(name="in_provision", value=False),
142 ]
143 weights: list[MPCVariable] = pydantic.Field(
144 default=[], description="Name and value of weights",
145 )
146 model_config = ConfigDict(json_encoders={MPCVariable: lambda v: v.dict()})
149class NFMPCData(BaseMPCData):
150 """Data class for PF-MPC"""
152 # files and paths
153 results_suffix: str = "_neg_flex.csv"
154 name_of_created_file: str = "neg_flex.json"
155 # modules
156 module_types: dict = cmng.SHADOW_MODULE_TYPE_DICT
157 class_name: str = "NegFlexModel"
158 module_id: str = "NegFlexMPC"
159 # variables
160 power_alias: str = glbs.POWER_ALIAS_NEG
161 stored_energy_alias: str = glbs.STORED_ENERGY_ALIAS_NEG
162 flex_cost_function: str = pydantic.Field(
163 default=None, description="Cost function of the NF-MPC",
164 )
165 # initialize market parameters with dummy values (0)
166 config_parameters_appendix: list[MPCVariable] = [
167 MPCVariable(name=glbs.PREP_TIME, value=0, unit="s"),
168 MPCVariable(name=glbs.MARKET_TIME, value=0, unit="s"),
169 MPCVariable(name=glbs.FLEX_EVENT_DURATION, value=0, unit="s")
170 ]
171 config_inputs_appendix: list[MPCVariable] = [
172 MPCVariable(name="in_provision", value=False),
173 ]
174 weights: list[MPCVariable] = pydantic.Field(
175 default=[], description="Name and value of weights",
176 )
177 model_config = ConfigDict(json_encoders={MPCVariable: lambda v: v.dict()})