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

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 

11 

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 

17 

18logger = logging.getLogger(__name__) 

19 

20 

21class AutoSettingNameMeta(type): 

22 """Adds the name to every SimulationSetting attribute based on its instance 

23 name. 

24 

25 This makes the definition of an extra attribute 'name' obsolete, as the 

26 attributes 'name' is automatic defined based on the instance name. 

27 

28 

29 Example: 

30 >>> # create new simulation settings for your awesome simulation 

31 >>> class MyAwesomeSimulationSettings(BaseSimSettings): 

32 ... def __init__(self): 

33 ... super().__init__() 

34 

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 ... ) 

47 

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""" 

58 

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 

67 

68 

69class SettingsManager(dict): 

70 """Manages the different settings of a SimulationSettings instance. 

71 

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. 

77 

78 Args: 

79 bound_simulation_settings: instance of sim_settings this manager is 

80 bound to. E.g. BuildingSimSettings. 

81 """ 

82 

83 def __init__(self, bound_simulation_settings): 

84 super().__init__() 

85 self.bound_simulation_settings = bound_simulation_settings 

86 self._create_settings() 

87 

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) 

93 

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)) 

102 

103 

104class Setting: 

105 """Define specific settings regarding model creation and simulation. 

106 

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 """ 

117 

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 

134 

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 

144 

145 def check_setting_config(self): 

146 """Checks if the setting is configured correctly""" 

147 return True 

148 

149 def load_default(self): 

150 if not self.value: 

151 self.value = self.default 

152 

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 

158 

159 return self._inner_get(bound_simulation_settings) 

160 

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 

164 

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 

168 

169 def check_value(self, bound_simulation_settings, value): 

170 """Checks the value that should be set for correctness 

171 

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 

181 

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) 

187 

188 

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 

202 

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 

225 

226 def check_value(self, bound_simulation_settings, value): 

227 """Checks the value that should be set for correctness 

228 

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}") 

250 

251 

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 

265 

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 

277 

278 def check_value(self, bound_simulation_settings, value): 

279 """Checks the value that should be set for correctness 

280 

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 

308 

309 

310class PathSetting(Setting): 

311 def check_value(self, bound_simulation_settings, value): 

312 """Checks the value that should be set for correctness 

313 

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 

334 

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) 

354 

355 

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 

363 

364 

365class BaseSimSettings(metaclass=AutoSettingNameMeta): 

366 """Specification of basic bim2sim simulation settings which are common for 

367 all simulations""" 

368 

369 def __init__(self, 

370 filters: list = None): 

371 self.manager = SettingsManager(bound_simulation_settings=self) 

372 

373 self.relevant_elements = {} 

374 self.simulated = False 

375 self.load_default_settings() 

376 

377 def load_default_settings(self): 

378 """loads default values for all settings""" 

379 for setting in self.manager.values(): 

380 setting.load_default() 

381 

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.') 

441 

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.") 

452 

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 ) 

472 

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 ) 

501 

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 ) 

511 

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 ) 

541 

542 

543class PlantSimSettings(BaseSimSettings): 

544 def __init__(self): 

545 super().__init__( 

546 ) 

547 self.relevant_elements = {*hvac_elements.items, Material} 

548 

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 ) 

575 

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 ) 

583 

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 ) 

590 

591class BuildingSimSettings(BaseSimSettings): 

592 

593 def __init__(self): 

594 super().__init__() 

595 self.relevant_elements = {*bps_elements.items, 

596 Material} 

597 

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" 

961 

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 )