1010from pathlib import Path
1111
1212import pandas as pd
13-
13+ from corrai . base . model import Model
1414from eppy .modeleditor import IDF
1515from eppy .runner .run_functions import run
1616import eppy .json_functions as json_functions
@@ -56,56 +56,7 @@ def temporary_directory():
5656 shutil .rmtree (temp_dir )
5757
5858
59- def expand_parameter_dict (parameter_dict , param_mappings ):
60- """
61- Expands a parameter dictionary based on predefined mappings.
62-
63- This method takes a dictionary of parameters and expands it by applying
64- predefined mappings stored in param_mappings. The expansion process works
65- as follows:
66-
67- 1. **If the mapping for a parameter is a dictionary**:
68- - The method checks if the value exists as a key in the mapping.
69- - If found, the corresponding mapped values are added to the expanded dictionary.
70-
71- 2. **If the mapping for a parameter is a list**:
72- - The method applies the value to each key in the mapping and adds
73- these key-value pairs to the expanded dictionary.
74-
75- 3. **If a parameter has no predefined mapping**:
76- - The original parameter and its value are added directly to the expanded
77- dictionary.
78-
79- Parameters
80- ----------
81- parameter_dict : dict
82- The original parameter dictionary, with parameter names as keys
83- and their values as values.
84- param_mappings: dict
85- A dictionary defining how sampled parameters should be expanded.
86-
87- Returns
88- -------
89- dict
90- An expanded parameter dictionary containing the original parameters along with
91- additional key-value pairs derived from the predefined mappings.
92-
93- """
94- expanded_dict = {}
95- for param_name , value in parameter_dict .items ():
96- if param_name in param_mappings :
97- mapping = param_mappings [param_name ]
98- if isinstance (mapping , dict ):
99- if value in mapping :
100- expanded_dict .update (mapping [value ])
101- else :
102- expanded_dict .update ({k : value for k in mapping })
103- else :
104- expanded_dict [param_name ] = value
105- return expanded_dict
106-
107-
108- class Building :
59+ class Building (Model ):
10960 """
11061 The Building class represents a building model. It is based on an EnergyPlus
11162 simulation file.
@@ -124,19 +75,20 @@ class Building:
12475 volume: Calculates and returns the total volume of the building in cubic meters.
12576 add_system(system): Adds an HVAC system to the building's systems.
12677 del_system(system_name): Deletes an HVAC system from the building's systems by name.
127- simulate(parameter_dict , simulation_options): Simulates the building model with
78+ simulate(property_dict , simulation_options): Simulates the building model with
12879 specified parameters and simulation options, returning the simulation results
12980 as a pandas DataFrame.
13081 """
13182
132- def __init__ (
133- self ,
134- idf_path ,
135- ):
83+ def __init__ (self , idf_path ):
84+ super ().__init__ (is_dynamic = True )
13685 self .idf = IDF (str (idf_path ))
13786 self ._idf_path = str (idf_path )
13887 self .systems = {category : [] for category in SystemCategories }
13988
89+ def get_property_values (self , property_list : list [str ]) -> list [str | int | float ]:
90+ return self .get_param_init_value (property_list )
91+
14092 @staticmethod
14193 def set_idd (root_eplus ):
14294 try :
@@ -214,8 +166,18 @@ def get_param_init_value(
214166 split_key = full_key .split ("." )
215167
216168 if split_key [0 ] == ParamCategories .IDF .value :
217- value = energytool .base .idf_utils .getidfvalue (working_idf , full_key )
218- values .append (value )
169+ if "*" in split_key :
170+ is_single = False
171+
172+ object_type = split_key [1 ]
173+ field_name = split_key [- 1 ]
174+
175+ objs = working_idf .idfobjects [object_type .upper ()]
176+ for obj in objs :
177+ values .append (getattr (obj , field_name ))
178+ else :
179+ value = energytool .base .idf_utils .getidfvalue (working_idf , full_key )
180+ values .append (value )
219181
220182 elif split_key [0 ] == ParamCategories .SYSTEM .value :
221183 if split_key [1 ].upper () in [sys .value for sys in SystemCategories ]:
@@ -236,15 +198,15 @@ def get_param_init_value(
236198
237199 def simulate (
238200 self ,
239- parameter_dict : dict [ str , str | float | int ] = None ,
240- simulation_options : dict [ str , str | float | int ] = None ,
241- idf_save_path : Path | None = None ,
242- param_mapping : dict = None ,
201+ property_dict = None ,
202+ simulation_options = None ,
203+ idf_save_path = None ,
204+ ** simulation_kwargs ,
243205 ) -> pd .DataFrame :
244206 """
245207 Simulate the building model with specified parameters and simulation options.
246208
247- :param parameter_dict : A dictionary containing key-value pairs representing
209+ :param property_dict : A dictionary containing key-value pairs representing
248210 parameters to be modified in the building model.
249211 These parameters can include changes to the IDF file, energytool HVAC system
250212 settings, or weather file.
@@ -286,25 +248,34 @@ def simulate(
286248 'STOP': '2023-01-31 23:59:59',
287249 'TIMESTEP': 900
288250 }
289- results = building.simulate(parameter_dict =parameter_changes,
251+ results = building.simulate(property_dict =parameter_changes,
290252 simulation_options=simulation_options)
291253
292254 """
255+ self .idf_save_path = idf_save_path
256+
293257 working_idf = deepcopy (self .idf )
294258 working_syst = deepcopy (self .systems )
295259
296260 epw_path = None
297- if parameter_dict is None :
298- parameter_dict = {}
299- if param_mapping :
300- parameter_dict = expand_parameter_dict (parameter_dict , param_mapping )
261+ if property_dict is None :
262+ property_dict = {}
301263
302- for key in parameter_dict :
264+ for key in property_dict :
303265 split_key = key .split ("." )
304266
305267 # IDF modification
306268 if split_key [0 ] == ParamCategories .IDF .value :
307- json_functions .updateidf (working_idf , {key : parameter_dict [key ]})
269+ if "*" in split_key :
270+ object_type = split_key [1 ]
271+ field_name = split_key [- 1 ]
272+ value = property_dict [key ]
273+
274+ objs = working_idf .idfobjects [object_type .upper ()]
275+ for obj in objs :
276+ setattr (obj , field_name , value )
277+ else :
278+ json_functions .updateidf (working_idf , {key : property_dict [key ]})
308279
309280 # In case it's a SYSTEM parameter, retrieve it in dict by category and name
310281 elif split_key [0 ] == ParamCategories .SYSTEM .value :
@@ -317,11 +288,11 @@ def simulate(
317288 )
318289 for syst in working_syst [sys_key ]:
319290 if syst .name == split_key [2 ]:
320- setattr (syst , split_key [3 ], parameter_dict [key ])
291+ setattr (syst , split_key [3 ], property_dict [key ])
321292
322293 # Meteo file
323294 elif split_key [0 ] == ParamCategories .EPW_FILE .value :
324- epw_path = parameter_dict [key ]
295+ epw_path = property_dict [key ]
325296 else :
326297 raise ValueError (
327298 f"{ split_key [0 ]} was not recognize as a valid parameter category"
@@ -333,11 +304,11 @@ def simulate(
333304 epw_path = simulation_options [SimuOpt .EPW_FILE .value ]
334305 except KeyError :
335306 raise ValueError (
336- "'epw_path' not found in parameter_dict nor in simulation_options"
307+ "'epw_path' not found in property_dict nor in simulation_options"
337308 )
338309 elif SimuOpt .EPW_FILE .value in list (simulation_options .keys ()):
339310 raise ValueError (
340- "'epw_path' have been used in both parameter_dict and "
311+ "'epw_path' have been used in both property_dict and "
341312 "simulation_options"
342313 )
343314 ref_year = None
@@ -397,8 +368,8 @@ def simulate(
397368 )
398369
399370 # Save IDF file after pre-process
400- if idf_save_path :
401- self .save (idf_save_path )
371+ if self . idf_save_path :
372+ working_idf .save (idf_save_path )
402373
403374 # POST-PROCESS
404375 return get_results (
0 commit comments