Coverage for bim2sim/sim_settings.py: 89%
239 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-12 17:09 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-12 17:09 +0000
1"""Module for defining simulation model specific process settings.
2This targets both, settings to set for the later simulation and settings for
3the model generation process in bim2sim.
4"""
5import logging
6import ast
7import os.path
8from pathlib import Path
9from typing import Union
10import sys
12from bim2sim.utilities import types
13from bim2sim.utilities.types import LOD
14from bim2sim.elements.base_elements import Material
15from bim2sim.elements import bps_elements as bps_elements, \
16 hvac_elements as hvac_elements
18logger = logging.getLogger(__name__)
21class AutoSettingNameMeta(type):
22 """Adds the name to every SimulationSetting attribute based on its instance
23 name.
25 This makes the definition of an extra attribute 'name' obsolete, as the
26 attributes 'name' is automatic defined based on the instance name.
29 Example:
30 >>> # create new simulation settings for your awesome simulation
31 >>> class MyAwesomeSimulationSettings(BaseSimSettings):
32 ... def __init__(self):
33 ... super().__init__()
35 >>> # create a new simulation setting, name will be taken automatic
36 from
37 >>> # instance name
38 >>> make_simulation_extra_fast = Setting(
39 ... default=True,
40 ... choices={
41 ... True: 'This simulation will be incredible fast.',
42 ... False: 'This simulation will be increbdile slow.'
43 ... },
44 ... description='Run the simulation in extra fast mode?',
45 ... for_frontend=True
46 ... )
48 >>> # create a SimulationSettings instance and get the value
49 >>> my_awesome_settings = MyAwesomeSimulationSettings()
50 >>> # get initial value which is always none
51 >>> print(my_awesome_settings.make_simulation_extra_fast)
52 None
53 >>> # set default values and get the value
54 >>> my_awesome_settings.load_default_settings()
55 >>> print(my_awesome_settings.make_simulation_extra_fast)
56 True
57"""
59 def __init__(cls, name, bases, namespace):
60 super(AutoSettingNameMeta, cls).__init__(name, bases, namespace)
61 # get all namespace objects
62 for name, obj in namespace.items():
63 # filter for settings of simulaiton
64 if isinstance(obj, Setting):
65 # provide name of the setting as attribute
66 obj.name = name
69class SettingsManager(dict):
70 """Manages the different settings of a SimulationSettings instance.
72 The manager is needed to maintain the different attributes of a simulation
73 (e.g. choices) while making the read and write access to the setting still
74 easy. This way you can call sim_settings.<setting_name> and get the value
75 directly while under sim_settings.manager.<setting_name> you can still find
76 all information.
78 Args:
79 bound_simulation_settings: instance of sim_settings this manager is
80 bound to. E.g. BuildingSimSettings.
81 """
83 def __init__(self, bound_simulation_settings):
84 super().__init__()
85 self.bound_simulation_settings = bound_simulation_settings
86 self._create_settings()
88 def _create_settings(self):
89 """Add all listed settings from the simulation in its attributes."""
90 for name in self.names:
91 setting = getattr(type(self.bound_simulation_settings), name)
92 setting.initialize(self)
94 @property
95 def names(self):
96 """Returns a generator object with all settings that the
97 bound_simulation_settings owns."""
98 return (name for name in dir(type(self.bound_simulation_settings))
99 if
100 isinstance(getattr(type(self.bound_simulation_settings), name),
101 Setting))
104class Setting:
105 """Define specific settings regarding model creation and simulation.
107 Args:
108 default: default value that will be applied when calling load_default()
109 choices: dict of possible choice for this setting as key and a
110 description per choice as value
111 description: description of what the settings does as Str
112 for_frontend: should this setting be shown in the frontend
113 multiple_choice: allows multiple choice
114 any_string: any string is allowed instead of a given choice
115 mandatory: whether a setting needs to be set
116 """
118 def __init__(
119 self,
120 default=None,
121 description: Union[str, None] = None,
122 for_frontend: bool = False,
123 any_string: bool = False,
124 mandatory=False
125 ):
126 self.name = None # set by AutoSettingNameMeta
127 self.default = default
128 self.value = None
129 self.description = description
130 self.for_webapp = for_frontend
131 self.any_string = any_string
132 self.mandatory = mandatory
133 self.manager = None
135 def initialize(self, manager):
136 """Link between manager stored setting and direct setting of simulation
137 """
138 if not self.name:
139 raise AttributeError("Attribute.name not set!")
140 self.check_setting_config()
141 self.manager = manager
142 self.manager[self.name] = self
143 self.manager[self.name].value = None
145 def check_setting_config(self):
146 """Checks if the setting is configured correctly"""
147 return True
149 def load_default(self):
150 if not self.value:
151 self.value = self.default
153 def __get__(self, bound_simulation_settings, owner):
154 """This is the get function that provides the value of the
155 simulation setting when calling sim_settings.<setting_name>"""
156 if bound_simulation_settings is None:
157 return self
159 return self._inner_get(bound_simulation_settings)
161 def _inner_get(self, bound_simulation_settings):
162 """Gets the value for the setting from the manager."""
163 return bound_simulation_settings.manager[self.name].value
165 def _inner_set(self, bound_simulation_settings, value):
166 """Sets the value for the setting inside the manager."""
167 bound_simulation_settings.manager[self.name].value = value
169 def check_value(self, bound_simulation_settings, value):
170 """Checks the value that should be set for correctness
172 Args:
173 bound_simulation_settings: the sim setting belonging to the value
174 value: value that should be checked for correctness
175 Returns:
176 True: if check was successful
177 Raises:
178 ValueError: if check was not successful
179 """
180 return True
182 def __set__(self, bound_simulation_settings, value):
183 """This is the set function that sets the value in the simulation
184 setting when calling sim_settings.<setting_name> = <value>"""
185 if self.check_value(bound_simulation_settings, value):
186 self._inner_set(bound_simulation_settings, value)
189class NumberSetting(Setting):
190 def __init__(
191 self,
192 default=None,
193 description: Union[str, None] = None,
194 for_frontend: bool = False,
195 any_string: bool = False,
196 min_value: float = None,
197 max_value: float = None
198 ):
199 super().__init__(default, description, for_frontend, any_string)
200 self.min_value = min_value
201 self.max_value = max_value
203 def check_setting_config(self):
204 """Make sure min and max values are reasonable"""
205 if not self.min_value:
206 self.min_value = sys.float_info.epsilon
207 logger.info(f'No min_value given for sim_setting {self}, assuming'
208 f'smallest float epsilon.')
209 if not self.max_value:
210 self.max_value = float('inf')
211 logger.info(f'No max_value given for sim_setting {self}, assuming'
212 f'biggest float inf.')
213 if self.default:
214 if self.default > self.max_value or self.default < self.min_value:
215 raise AttributeError(
216 f"The specified limits for min_value, max_value and"
217 f"default are contradictory min: {self.min_value} "
218 f"max: {self.max_value}")
219 if self.min_value > self.max_value:
220 raise AttributeError(
221 f"The specified limits for min_value and max_value are "
222 f"contradictory min: {self.min_value} max: {self.max_value}")
223 else:
224 return True
226 def check_value(self, bound_simulation_settings, value):
227 """Checks the value that should be set for correctness
229 Checks if value is in limits.
230 Args:
231 bound_simulation_settings: the sim setting belonging to the value
232 value: value that should be checked for correctness
233 Returns:
234 True: if check was successful
235 Raises:
236 ValueError: if check was not successful
237 """
238 # None is allowed for settings that should not be used at all but have
239 # number values if used
240 if value is None:
241 return True
242 if not isinstance(value, (float, int)):
243 raise ValueError("The provided value is not a number.")
244 if self.min_value <= value <= self.max_value:
245 return True
246 else:
247 raise ValueError(
248 f"The provided value is not inside the limits: min: "
249 f"{self.min_value}, max: {self.max_value}, value: {value}")
252class ChoiceSetting(Setting):
253 def __init__(
254 self,
255 default=None,
256 description: Union[str, None] = None,
257 for_frontend: bool = False,
258 any_string: bool = False,
259 choices: dict = None,
260 multiple_choice: bool = False
261 ):
262 super().__init__(default, description, for_frontend, any_string)
263 self.choices = choices
264 self.multiple_choice = multiple_choice
266 def check_setting_config(self):
267 """make sure str choices don't hold '.' as this is seperator for enums.
268 """
269 for choice in self.choices:
270 if isinstance(choice, str) and '.' in choice:
271 if '.' in choice:
272 raise AttributeError(
273 f"Provided setting {choice} has a choice with "
274 f"character"
275 f" '.', this is prohibited.")
276 return True
278 def check_value(self, bound_simulation_settings, value):
279 """Checks the value that should be set for correctness
281 Checks if the selected value is in choices.
282 Args:
283 bound_simulation_settings: the sim setting belonging to the value
284 value: value that should be checked for correctness
285 Returns:
286 True: if check was successful
287 Raises:
288 ValueError: if check was not successful
289 """
290 choices = bound_simulation_settings.manager[self.name].choices
291 if isinstance(value, list):
292 if not self.multiple_choice:
293 raise ValueError(f'Only one choice is allowed for setting'
294 f' {self.name}, but {len(value)} choices '
295 f'are given.')
296 for val in value:
297 self.check_value(bound_simulation_settings, val)
298 return True
299 else:
300 if self.any_string and not isinstance(value, str):
301 raise ValueError(f'{value} is no valid value for setting '
302 f'{self.name}, please enter a string.')
303 elif value not in choices and not self.any_string:
304 raise ValueError(f'{value} is no valid value for setting '
305 f'{self.name}, select one of {choices}.')
306 else:
307 return True
310class PathSetting(Setting):
311 def check_value(self, bound_simulation_settings, value):
312 """Checks the value that should be set for correctness
314 Checks if the value is a valid path
315 Args:
316 bound_simulation_settings: the sim setting belonging to the value
317 value: value that should be checked for correctness
318 Returns:
319 True: if check was successful
320 Raises:
321 ValueError: if check was not successful
322 """
323 # check for existence
324 # TODO #556 Do not check default path for existence because this might
325 # not exist on system. This is a hack and should be solved when
326 # improving communication between config and settings
327 if not value == self.default:
328 if not value.exists():
329 raise FileNotFoundError(
330 f"The path provided for '{self.name}' does not exist."
331 f" Please check the provided setting path which is: "
332 f"{str(value)}")
333 return True
335 def __set__(self, bound_simulation_settings, value):
336 """This is the set function that sets the value in the simulation
337 setting
338 when calling sim_settings.<setting_name> = <value>"""
339 if not isinstance(value, Path):
340 if value is not None:
341 try:
342 value = Path(value)
343 except TypeError:
344 raise TypeError(
345 f"Could not convert the simulation setting for "
346 f"{self.name} into a path, please check the path.")
347 # if default value is None this is ok
348 elif value == self.default:
349 pass
350 else:
351 raise ValueError(f"No Path provided for setting {self.name}.")
352 if self.check_value(bound_simulation_settings, value):
353 self._inner_set(bound_simulation_settings, value)
356class BooleanSetting(Setting):
357 def check_value(self, bound_simulation_settings, value):
358 if not isinstance(value, bool) and value is not None:
359 raise ValueError(f"The provided value {value} for sim_setting "
360 f"{self.name} is not a Boolean")
361 else:
362 return True
365class BaseSimSettings(metaclass=AutoSettingNameMeta):
366 """Specification of basic bim2sim simulation settings which are common for
367 all simulations"""
369 def __init__(self,
370 filters: list = None):
371 self.manager = SettingsManager(bound_simulation_settings=self)
373 self.relevant_elements = {}
374 self.simulated = False
375 self.load_default_settings()
377 def load_default_settings(self):
378 """loads default values for all settings"""
379 for setting in self.manager.values():
380 setting.load_default()
382 def update_from_config(self, config):
383 """Updates the simulation settings specification from the config
384 file"""
385 n_loaded_settings = 0
386 for cat, settings in config.items():
387 # don't load settings which are not simulation relevant
388 if cat.lower() not in [
389 self.__class__.__name__.lower(),
390 'Generic Simulation Settings'
391 ]:
392 continue
393 cat_from_cfg = config[cat]
394 for setting in settings:
395 if not hasattr(self, setting):
396 raise AttributeError(
397 f'{setting} is no allowed setting for '
398 f'simulation {self.__class__.__name__} ')
399 else:
400 set_from_cfg = cat_from_cfg.get(setting)
401 if set_from_cfg is None:
402 continue
403 elif isinstance(set_from_cfg, str):
404 # convert to readable python object
405 try:
406 # todo ast.literal_eval is safer but not safe.
407 set_from_cfg = ast.literal_eval(str(set_from_cfg))
408 except (ValueError, SyntaxError):
409 logger.warning(f'Failed literal evaluation of '
410 f'{set_from_cfg}. Proceeding.')
411 if isinstance(set_from_cfg, str):
412 # handle all strings that are file paths, before
413 # handling Enums
414 if os.path.isfile(set_from_cfg):
415 val = set_from_cfg
416 # handle Enums (will not be found by literal_eval)
417 elif isinstance(set_from_cfg, str) and \
418 '.' in set_from_cfg:
419 enum_type, enum_val = set_from_cfg.split('.')
420 # convert str to enum
421 try:
422 enum_type = getattr(types, enum_type)
423 val = getattr(enum_type, enum_val)
424 except AttributeError:
425 raise AttributeError(
426 f" Tried to create the enumeration "
427 f"{enum_type} but it doesn't exist.")
428 else:
429 # handle all other strings
430 val = set_from_cfg
431 else:
432 # handle all other data types
433 val = set_from_cfg
434 setattr(self, setting, val)
435 n_loaded_settings += 1
436 else:
437 raise TypeError(
438 f'Config entry for {setting} is no string. '
439 f'Please use strings only in config.')
440 logger.info(f'Loaded {n_loaded_settings} settings from config file.')
442 def check_mandatory(self):
443 """Check if mandatory settings have a value."""
444 for setting in self.manager.values():
445 if setting.mandatory:
446 if not setting.value:
447 raise ValueError(
448 f"Attempted to run project. Simulation setting "
449 f"{setting.name} is not specified, "
450 f"but is marked as mandatory. Please configure "
451 f"{setting.name} before running your project.")
453 dymola_simulation = BooleanSetting(
454 default=False,
455 description='Run a Simulation with Dymola after model export?',
456 for_frontend=True
457 )
458 create_external_elements = BooleanSetting(
459 default=False,
460 description='Create external elements?',
461 for_frontend=True
462 )
463 max_wall_thickness = NumberSetting(
464 default=0.3,
465 max_value=0.60,
466 min_value=1e-3,
467 description='Choose maximum wall thickness as a tolerance for mapping '
468 'opening boundaries to their base surface (Wall). '
469 'Choose 0.3m as a default value.',
470 for_frontend=True
471 )
473 group_unidentified = ChoiceSetting(
474 default='fuzzy',
475 choices={
476 'fuzzy': 'Use fuzzy search to find name similarities',
477 'name': 'Only group elements with exact same name'
478 },
479 description='To reduce the number of decisions by user to identify '
480 'elements which can not be identified automatically by '
481 'the '
482 'system, you can either use simple grouping by same name '
483 'of'
484 ' IFC element or fuzzy search to group based on'
485 ' similarities in name.',
486 for_frontend=True
487 )
488 fuzzy_threshold = NumberSetting(
489 default=0.7,
490 min_value=0.5,
491 max_value=0.9,
492 description='If you want to use fuzzy search in the '
493 'group_unidentified '
494 'setting, you can set the threshold here. A low '
495 'threshold means'
496 ' a small similarity is required for grouping. A too low '
497 'value '
498 'might result in grouping elements which do not represent '
499 'the same IFC type.'
500 )
502 reset_guids = BooleanSetting(
503 default=False,
504 description='Reset GlobalIDs from imported IFC if duplicate '
505 'GlobalIDs occur in the IFC. As EnergyPlus evaluates all'
506 'GlobalIDs upper case only, this might also be '
507 'applicable if duplicate non-case-sensitive GlobalIDs '
508 'occur.',
509 for_frontend=True
510 )
512 weather_file_path = PathSetting(
513 default=None,
514 description='Path to the weather file that should be used for the '
515 'simulation. If no path is provided, we will try to get '
516 'the'
517 'location from the IFC and download a fitting weather'
518 ' file. For Modelica provide .mos files, for EnergyPlus '
519 '.epw files. If the format does not fit, we will try to '
520 'convert.',
521 for_frontend=True,
522 mandatory=True
523 )
524 add_space_boundaries = BooleanSetting(
525 default=False,
526 description='Add space boundaries. Only required for building '
527 'performance simulation and co-simulations.',
528 for_frontend=True
529 )
530 correct_space_boundaries = BooleanSetting(
531 default=False,
532 description='Apply geometric correction to space boundaries.',
533 for_frontend=True
534 )
535 close_space_boundary_gaps = BooleanSetting(
536 default=False,
537 description='Close gaps in the set of space boundaries by adding '
538 'additional 2b space boundaries.',
539 for_frontend=True
540 )
543class PlantSimSettings(BaseSimSettings):
544 def __init__(self):
545 super().__init__(
546 )
547 self.relevant_elements = {*hvac_elements.items, Material}
549 # Todo maybe make every aggregation its own setting with LOD in the future,
550 # but currently we have no usage for this afaik.
551 aggregations = ChoiceSetting(
552 default=[
553 'UnderfloorHeating',
554 'PipeStrand',
555 'Consumer',
556 'ParallelPump',
557 'ConsumerHeatingDistributorModule',
558 'GeneratorOneFluid',
559 ],
560 choices={
561 'UnderfloorHeating': 'Aggregate underfloor heating circuits',
562 'Consumer': 'Aggregate consumers',
563 'PipeStrand': 'Aggregate strands of pipes',
564 'ParallelPump': 'Aggregate parallel pumps',
565 'ConsumerHeatingDistributorModule': 'Aggregate consumer and '
566 'distributor to one module',
567 'GeneratorOneFluid': 'Aggregate the generator and its circuit to '
568 'one module',
569 },
570 description="Which aggregations should be applied on the hydraulic "
571 "network",
572 multiple_choice=True,
573 for_frontend=True
574 )
576 tolerance_connect_by_position = NumberSetting(
577 default=10,
578 description="Tolerance for distance for which ports should be "
579 "connected. Based on there position in IFC.",
580 for_frontend=True,
581 min_value=1
582 )
584 verify_connection_by_position = BooleanSetting(
585 description="Choose if connection of elements via IfcDistributionPorts"
586 " should be validated by the geometric position of the "
587 "ports.",
588 default=True
589 )
591class BuildingSimSettings(BaseSimSettings):
593 def __init__(self):
594 super().__init__()
595 self.relevant_elements = {*bps_elements.items,
596 Material}
598 layers_and_materials = ChoiceSetting(
599 default=LOD.low,
600 choices={
601 LOD.low: 'Override materials with predefined setups',
602 # LOD.full: 'Get all information from IFC and enrich if needed'
603 },
604 description='Select how existing Material information in IFC should '
605 'be treated.',
606 for_frontend=True
607 )
608 year_of_construction_overwrite = NumberSetting(
609 default=None,
610 min_value=0,
611 max_value=2015,
612 description="Force an overwrite of the year of construction as a "
613 "base for the selected construction set.",
614 for_frontend=True,
615 )
616 construction_class_walls = ChoiceSetting(
617 default='iwu_heavy',
618 choices={
619 'iwu_heavy': 'Wall structures according to iwu heavy standard',
620 'iwu_light': 'Wall structures according to iwu light standard',
621 'kfw_40': 'Wall structures according to kfw 40 standard',
622 'kfw_55': 'Wall structures according to kfw 55 standard',
623 'kfw_70': 'Wall structures according to kfw 70 standard',
624 'kfw_85': 'Wall structures according to kfw 85 standard',
625 'kfw_100': 'Wall structures according to kfw 100 standard',
626 'tabula_de_standard_1_SFH': 'Wall structures according to german '
627 'tabula standard 1 for single family '
628 'houses',
629 'tabula_de_standard_2_SFH': 'Wall structures according to german '
630 'tabula standard 2 for single family '
631 'houses',
632 'tabula_de_retrofit_1_SFH': 'Wall structures according to german '
633 'tabula retrofit 1 for single family '
634 'houses',
635 'tabula_de_retrofit_2_SFH': 'Wall structures according to german '
636 'tabula retrofit 2 for single family '
637 'houses',
638 'tabula_de_adv_retrofit_1_SFH': 'Wall structures according to '
639 'german tabula advanced retrofit '
640 '1 for single '
641 'family houses',
642 'tabula_de_adv_retrofit_2_SFH': 'Wall structures according to '
643 'german tabula advanced retrofit '
644 '2 for '
645 'single family houses',
646 'tabula_de_standard_1_TH': 'Wall structures according to german '
647 'tabula standard 1 for terraced houses',
648 'tabula_de_standard_2_TH': 'Wall structures according to german '
649 'tabula standard 2 for terraced houses',
650 'tabula_de_retrofit_1_TH': 'Wall structures according to german '
651 'tabula retrofit 1 for terraced houses',
652 'tabula_de_retrofit_2_TH': 'Wall structures according to german '
653 'tabula retrofit 2 for terraced houses',
654 'tabula_de_standard_1_MFH': 'Wall structures according to german '
655 'tabula standard 1 for multi family '
656 'houses',
657 'tabula_de_retrofit_1_MFH': 'Wall structures according to german '
658 'tabula retrofit 1 for multi family '
659 'houses',
660 'tabula_de_adv_retrofit_1_MFH': 'Wall structures according to '
661 'german tabula advanced retrofit '
662 '1 for multi '
663 'family houses',
664 'tabula_de_standard_1_AB': 'Wall structures according to german '
665 'tabula standard 1 for apartment '
666 'blocks',
667 'tabula_de_adv_retrofit_1_AB': 'Wall structures according to '
668 'german tabula advanced retrofit '
669 '1 for '
670 'apartment blocks',
671 'tabula_de_standard': 'Wall structures according to german '
672 'tabula standard',
673 'tabula_dk_standard_1_SFH': 'Wall structures according to danish '
674 'tabula standard 1 for single family '
675 'houses',
676 'tabula_dk_standard_2_SFH': 'Wall structures according to danish '
677 'tabula standard 2 for single family '
678 'houses',
679 'tabula_dk_retrofit_1_SFH': 'Wall structures according to danish '
680 'tabula retrofit 1 for single family '
681 'houses',
682 'tabula_dk_retrofit_2_SFH': 'Wall structures according to danish '
683 'tabula retrofit 2 for single family '
684 'houses',
685 'tabula_dk_adv_retrofit_1_SFH': 'Wall structures according to '
686 'danish tabula advanced retrofit '
687 '1 for single '
688 'family houses',
689 'tabula_dk_adv_retrofit_2_SFH': 'Wall structures according to '
690 'danish tabula advanced retrofit '
691 '2 for single '
692 'family houses',
693 'tabula_dk_standard_1_TH': 'Wall structures according to danish '
694 'tabula standard 1 for terraced houses',
695 'tabula_dk_standard_2_TH': 'Wall structures according to danish '
696 'tabula standard 2 for terraced houses',
697 'tabula_dk_retrofit_1_TH': 'Wall structures according to danish '
698 'tabula retrofit 1 for terraced houses',
699 'tabula_dk_retrofit_2_TH': 'Wall structures according to danish '
700 'tabula retrofit 1 for terraced houses',
701 'tabula_dk_adv_retrofit_1_TH': 'Wall structures according to '
702 'danish tabula advanced retrofit '
703 '1 for '
704 'terraced houses',
705 'tabula_dk_adv_retrofit_2_TH': 'Wall structures according to '
706 'danish tabula advanced retrofit '
707 '1 for '
708 'terraced houses',
709 'tabula_dk_standard_1_AB': 'Wall structures according to danish '
710 'tabula standard 1 for apartment '
711 'blocks',
712 'tabula_dk_standard_2_AB': 'Wall structures according to danish '
713 'tabula standard 2 for apartment '
714 'blocks',
715 'tabula_dk_retrofit_1_AB': 'Wall structures according to danish '
716 'tabula retrofit 1 for apartment '
717 'blocks',
718 'tabula_dk_retrofit_2_AB': 'Wall structures according to danish '
719 'tabula retrofit 2 for apartment '
720 'blocks',
721 'tabula_dk_adv_retrofit_1_AB': 'Wall structures according to '
722 'danish tabula advanced retrofit '
723 '1 for '
724 'apartment blocks',
725 'tabula_dk_adv_retrofit_2_AB': 'Wall structures according to '
726 'danish tabula advanced retrofit '
727 '2 for '
728 'apartment blocks',
729 'tabula_dk_standard': 'Wall structures according to danish '
730 'tabula standard'
731 },
732 description="Select the most fitting construction class type for"
733 "the walls of the selected building. For all settings but "
734 "kfw_* the year of construction is required.",
735 for_frontend=True
736 )
737 construction_class_windows = ChoiceSetting(
738 default='Alu- oder Stahlfenster, Waermeschutzverglasung, zweifach',
739 choices={
740 'Holzfenster, zweifach':
741 'Zeifachverglasung mit Holzfenstern',
742 'Kunststofffenster, Isolierverglasung':
743 'Isolierverglasung mit Kunststofffensern',
744 'Alu- oder Stahlfenster, Isolierverglasung':
745 'Isolierverglasung mit Alu- oder Stahlfenstern',
746 'Alu- oder Stahlfenster, Waermeschutzverglasung, zweifach':
747 'Wärmeschutzverglasung (zweifach) mit Alu- oder '
748 'Stahlfenstern',
749 'Waermeschutzverglasung, dreifach':
750 'Wärmeschutzverglasung (dreifach)',
751 'tabula_de_standard_1_SFH': 'Windows according to german tabula '
752 'standard 1 for single family '
753 'houses',
754 'tabula_de_standard_2_SFH': 'Windows according to german tabula '
755 'standard 2 for single family '
756 'houses',
757 'tabula_de_retrofit_1_SFH': 'Windows according to german tabula '
758 'retrofit 1 for single family '
759 'houses',
760 'tabula_de_retrofit_2_SFH': 'Windows according to german tabula '
761 'retrofit 2 for single family '
762 'houses',
763 'tabula_de_adv_retrofit_1_SFH': 'Windows according to german '
764 'tabula advanced retrofit 1 for '
765 'single '
766 'family houses',
767 'tabula_de_adv_retrofit_2_SFH': 'Windows according to german '
768 'tabula advanced retrofit 2 for '
769 'single family houses',
770 'tabula_de_standard_1_TH': 'Windows according to german tabula '
771 'standard 1 for terraced houses',
772 'tabula_de_standard_2_TH': 'Windows according to german tabula '
773 'standard 2 for terraced houses',
774 'tabula_de_retrofit_1_TH': 'Windows according to german tabula '
775 'retrofit 1 for terraced houses',
776 'tabula_de_retrofit_2_TH': 'Windows according to german tabula '
777 'retrofit 2 for terraced houses',
778 'tabula_de_standard_1_MFH': 'Windows according to german tabula '
779 'standard 1 for multi family houses',
780 'tabula_de_retrofit_1_MFH': 'Windows according to german tabula '
781 'retrofit 1 for multi family houses',
782 'tabula_de_adv_retrofit_1_MFH': 'Windows according to german '
783 'tabula advanced retrofit 1 for '
784 'multi '
785 'family houses',
786 'tabula_de_standard_1_AB': 'Windows according to german tabula '
787 'standard 1 for apartment blocks',
788 'tabula_de_adv_retrofit_1_AB': 'Windows according to german '
789 'tabula advanced retrofit 1 for '
790 'apartment blocks',
791 'tabula_de_standard': 'Windows according to german tabula '
792 'standard',
793 'tabula_dk_standard_1_SFH': 'Windows according to danish tabula '
794 'standard 1 for single family '
795 'houses',
796 'tabula_dk_standard_2_SFH': 'Windows according to danish tabula '
797 'standard 2 for single family '
798 'houses',
799 'tabula_dk_retrofit_1_SFH': 'Windows according to danish tabula '
800 'retrofit 1 for single family '
801 'houses',
802 'tabula_dk_retrofit_2_SFH': 'Windows according to danish tabula '
803 'retrofit 2 for single family '
804 'houses',
805 'tabula_dk_adv_retrofit_1_SFH': 'Windows according to danish '
806 'tabula advanced retrofit 1 for '
807 'single '
808 'family houses',
809 'tabula_dk_adv_retrofit_2_SFH': 'Windows according to danish '
810 'tabula advanced retrofit 2 for '
811 'single '
812 'family houses',
813 'tabula_dk_standard_1_TH': 'Windows according to danish tabula '
814 'standard 1 for terraced houses',
815 'tabula_dk_standard_2_TH': 'Windows according to danish tabula '
816 'standard 2 for terraced houses',
817 'tabula_dk_retrofit_1_TH': 'Windows according to danish tabula '
818 'retrofit 1 for terraced houses',
819 'tabula_dk_retrofit_2_TH': 'Windows according to danish tabula '
820 'retrofit 1 for terraced houses',
821 'tabula_dk_adv_retrofit_1_TH': 'Windows according to danish '
822 'tabula advanced retrofit 1 for '
823 'terraced houses',
824 'tabula_dk_adv_retrofit_2_TH': 'Windows according to danish '
825 'tabula advanced retrofit 1 for '
826 'terraced houses',
827 'tabula_dk_standard_1_AB': 'Windows according to danish tabula '
828 'standard 1 for apartment blocks',
829 'tabula_dk_standard_2_AB': 'Windows according to danish tabula '
830 'standard 2 for apartment blocks',
831 'tabula_dk_retrofit_1_AB': 'Windows according to danish tabula '
832 'retrofit 1 for apartment blocks',
833 'tabula_dk_retrofit_2_AB': 'Windows according to danish tabula '
834 'retrofit 2 for apartment blocks',
835 'tabula_dk_adv_retrofit_1_AB': 'Windows according to danish '
836 'tabula advanced retrofit 1 for '
837 'apartment blocks',
838 'tabula_dk_adv_retrofit_2_AB': 'Windows according to danish '
839 'tabula advanced retrofit 2 for '
840 'apartment blocks',
841 'tabula_dk_standard': 'Windows according to danish tabula standard'
842 },
843 description="Select the most fitting construction class type for"
844 " the windows of the selected building.",
845 )
846 construction_class_doors = ChoiceSetting(
847 default='iwu_typical',
848 choices={
849 'iwu_typical': 'Typical door data based',
850 'kfw_40': 'Doors according to kfw 40 standard',
851 'kfw_55': 'Doors according to kfw 55 standard',
852 'kfw_70': 'Doors according to kfw 70 standard',
853 'kfw_85': 'Doors according to kfw 85 standard',
854 'kfw_100': 'Doors according to kfw 100 standard',
855 'tabula_de_standard_1_SFH': 'Windows according to german tabula '
856 'standard 1 for single family '
857 'houses',
858 'tabula_de_retrofit_1_SFH': 'Windows according to german tabula '
859 'retrofit 1 for single family '
860 'houses',
861 'tabula_de_adv_retrofit_1_SFH': 'Windows according to german '
862 'tabula advanced retrofit 1 for '
863 'single '
864 'family houses',
865 'tabula_de_standard_1_TH': 'Windows according to german tabula '
866 'standard 1 for terraced houses',
867 'tabula_de_retrofit_1_TH': 'Windows according to german tabula '
868 'retrofit 1 for terraced houses',
869 'tabula_de_adv_retrofit_1_TH': 'Windows according to german '
870 'tabula advanced retrofit 1 for '
871 'terraced houses',
872 'tabula_de_standard_1_MFH': 'Windows according to german tabula '
873 'standard 1 for multi family houses',
874 'tabula_de_retrofit_1_MFH': 'Windows according to german tabula '
875 'retrofit 1 for multi family houses',
876 'tabula_de_adv_retrofit_1_MFH': 'Windows according to german '
877 'tabula advanced retrofit 1 for '
878 'multi '
879 'family houses',
880 'tabula_de_standard_1_AB': 'Windows according to german tabula '
881 'standard 1 for apartment blocks',
882 'tabula_de_retrofit_1_AB': 'Windows according to german tabula '
883 'retrofit 1 for apartment blocks',
884 'tabula_de_adv_retrofit_1_AB': 'Windows according to german '
885 'tabula advanced retrofit 1 for '
886 'apartment blocks',
887 'tabula_dk_standard_1_SFH': 'Windows according to danish tabula '
888 'standard 1 for single family '
889 'houses'
890 },
891 description="Select the most fitting construction class type for"
892 " the windows of the selected building.",
893 )
894 heating_tz_overwrite = BooleanSetting(
895 default=None,
896 description='If True, all thermal zones will be provided with heating,'
897 'if False no heating for thermal zones is provided, '
898 'regardless of information in the IFC or in the use '
899 'condition file.',
900 for_frontend=True
901 )
902 cooling_tz_overwrite = BooleanSetting(
903 default=None,
904 description='If True, all thermal zones will be provided with cooling,'
905 'if False no cooling for thermal zones is provided, '
906 'regardless of information in the IFC or in the use '
907 'condition file.',
908 for_frontend=True
909 )
910 ahu_tz_overwrite = BooleanSetting(
911 default=None,
912 description='If True, all thermal zones will be provided with AHU,'
913 'if False no AHU for thermal zones is provided, '
914 'regardless of information in the IFC or in the use '
915 'condition file.',
916 for_frontend=True
917 )
918 prj_use_conditions = PathSetting(
919 default=None,
920 description="Path to a custom UseConditions.json for the specific "
921 "project, that holds custom usage conditions for this "
922 "project. If this is used, this use_conditions file have "
923 "to hold all information. The basic UseConditions.json "
924 "file is ignored in this case.",
925 for_frontend=True
926 )
927 prj_custom_usages = PathSetting(
928 default=None,
929 description="Path to a custom customUsages.json for the specific "
930 "project, that holds mappings between space names from "
931 "IFC "
932 "and usage conditions from UseConditions.json.",
933 for_frontend=True
934 )
935 setpoints_from_template = BooleanSetting(
936 default=False,
937 description="Use template heating and cooling profiles instead of "
938 "setpoints from IFC. Defaults to False, i.e., "
939 "use original data source. Set to True, "
940 "if template-based values should be used instead.",
941 for_frontend=True
942 )
943 use_maintained_illuminance = BooleanSetting(
944 default=True,
945 description="Use maintained illuminance required per zone based on "
946 "DIN V EN 18599 information to calculate internal loads"
947 "through lighting.",
948 for_frontend=True
949 )
950 sim_results = ChoiceSetting(
951 default=[
952 "heat_demand_total", "cool_demand_total",
953 "heat_demand_rooms", "cool_demand_rooms",
954 "heat_energy_total", "cool_energy_total",
955 "heat_energy_rooms", "cool_energy_rooms",
956 "air_temp_out", "operative_temp_rooms", "air_temp_rooms",
957 "internal_gains_machines_rooms", "internal_gains_persons_rooms",
958 "internal_gains_lights_rooms", "n_persons_rooms",
959 "infiltration_rooms", "mech_ventilation_rooms",
960 "heat_set_rooms", "cool_set_rooms"
962 ],
963 choices={
964 "heat_demand_total":
965 "Total heating demand (power) as time series data",
966 "cool_demand_total":
967 "Total cooling demand (power) as time series data",
968 "heat_demand_rooms":
969 "Zone based heating demand (power) as time series data",
970 "cool_demand_rooms":
971 "Zone based cooling demand (power) as time series data",
972 "heat_energy_total":
973 "Total heating energy as time series data",
974 "cool_energy_total":
975 "Total cooling energy as time series data",
976 "heat_energy_rooms":
977 "Zone based heating energy as time series data",
978 "cool_energy_rooms":
979 "Zone cooling heating energy as time series data",
980 "air_temp_out":
981 "Outdoor air temperature as time series data",
982 "operative_temp_rooms":
983 "Zone based operative temperature as time series data",
984 "air_temp_rooms":
985 "Zone based indoor air temperature as time series data",
986 "internal_gains_machines_rooms":
987 "Internal gains through machines in W as time series data",
988 "internal_gains_persons_rooms":
989 "Internal gains through persons in W as time series data",
990 "internal_gains_lights_rooms":
991 "Internal gains through lights in W as time series data",
992 "n_persons_rooms":
993 "Total amount of occupying persons as time series data",
994 "infiltration_rooms":
995 "Infiltration into room in 1/h as time series data",
996 "mech_ventilation_rooms":
997 "Mechanical ventilation flow in m³/h as time series data",
998 "heat_set_rooms":
999 "Heating set point in °C time series data",
1000 "cool_set_rooms":
1001 "Cooling set point in °C time series data",
1002 },
1003 multiple_choice=True,
1004 )
1005 add_space_boundaries = BooleanSetting(
1006 default=True,
1007 description='Add space boundaries. Only required for building '
1008 'performance simulation and co-simulations.',
1009 for_frontend=True
1010 )
1011 correct_space_boundaries = BooleanSetting(
1012 default=False,
1013 description='Apply geometric correction to space boundaries.',
1014 for_frontend=True
1015 )
1016 split_bounds = BooleanSetting(
1017 default=False,
1018 description='Whether to convert up non-convex space boundaries or '
1019 'not.',
1020 for_frontend=True
1021 )
1022 add_shadings = BooleanSetting(
1023 default=False,
1024 description='Whether to add shading surfaces if available or not.',
1025 for_frontend=True
1026 )
1027 split_shadings = BooleanSetting(
1028 default=False,
1029 description='Whether to convert up non-convex shading boundaries or '
1030 'not.',
1031 for_frontend=True
1032 )
1033 close_space_boundary_gaps = BooleanSetting(
1034 default=False,
1035 description='Close gaps in the set of space boundaries by adding '
1036 'additional 2b space boundaries.',
1037 for_frontend=True
1038 )
1039 create_plots = BooleanSetting(
1040 default=False,
1041 description='Create plots for simulation results after the simulation '
1042 'finished.',
1043 for_frontend=True
1044 )
1045 set_run_period = BooleanSetting(
1046 default=False,
1047 description="Choose whether run period for simulation execution "
1048 "should be set manually instead of running annual "
1049 "simulation."
1050 )
1051 run_period_start_month = NumberSetting(
1052 default=1,
1053 min_value=1,
1054 max_value=12,
1055 description="Choose start month of run period. Requires "
1056 "set_run_period==True for activation.",
1057 for_frontend=True
1058 )
1059 run_period_start_day = NumberSetting(
1060 default=1,
1061 min_value=1,
1062 max_value=31,
1063 description="Choose start day of run period. Requires "
1064 "set_run_period==True for activation.",
1065 for_frontend=True
1066 )
1067 run_period_end_month = NumberSetting(
1068 default=12,
1069 min_value=1,
1070 max_value=12,
1071 description="Choose end month of run period. Requires "
1072 "set_run_period==True for activation.",
1073 for_frontend=True
1074 )
1075 run_period_end_day = NumberSetting(
1076 default=31,
1077 min_value=1,
1078 max_value=31,
1079 description="Choose end day of run period. Requires "
1080 "set_run_period==True for activation.",
1081 for_frontend=True
1082 )
1083 plot_singe_zone_guid = ChoiceSetting(
1084 default='',
1085 choices={'': "Skip"},
1086 description="Choose the GlobalId of the IfcSpace for which results "
1087 "should be plotted.",
1088 any_string=True
1089 )
1090 ahu_heating_overwrite = BooleanSetting(
1091 default=None,
1092 description="Choose if the central AHU should provide heating. "
1093 )
1094 ahu_cooling_overwrite = BooleanSetting(
1095 default=None,
1096 description="Choose if the central AHU should provide cooling."
1097 )
1098 ahu_dehumidification_overwrite = BooleanSetting(
1099 default=None,
1100 description="Choose if the central AHU should provide "
1101 "dehumidification."
1102 )
1103 ahu_humidification_overwrite = BooleanSetting(
1104 default=None,
1105 description="Choose if the central AHU should provide humidification."
1106 "otherwise this has no effect. "
1107 )
1108 ahu_heat_recovery_overwrite = BooleanSetting(
1109 default=None,
1110 description="Choose if the central AHU should zuse heat recovery."
1111 )
1112 ahu_heat_recovery_efficiency_overwrite = NumberSetting(
1113 default=None,
1114 min_value=0.5,
1115 max_value=0.99,
1116 description="Choose the heat recovery efficiency of the central AHU."
1117 )
1118 use_constant_infiltration_overwrite = BooleanSetting(
1119 default=None,
1120 description="If only constant base infiltration should be used and no "
1121 "dynamic ventilation through e.g. windows."
1122 )
1123 base_infiltration_rate_overwrite = NumberSetting(
1124 default=None,
1125 min_value=0.001,
1126 max_value=5,
1127 description="Overwrite base value for the natural infiltration in 1/h "
1128 " without window openings"
1129 )