Coverage for teaser/logic/buildingobjects/building.py: 80%

354 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2025-04-29 16:01 +0000

1# created June 2015 

2# by TEASER4 Development Team 

3 

4"""This module includes the Building class 

5""" 

6import inspect 

7import random 

8import re 

9import warnings 

10from teaser.logic.buildingobjects.calculation.aixlib import AixLib 

11from teaser.logic.buildingobjects.calculation.ibpsa import IBPSA 

12 

13 

14from teaser.logic.buildingobjects.buildingsystems.buildingahu import BuildingAHU 

15 

16 

17class Building(object): 

18 """Building Class 

19 

20 This class is used to manage information and parameter calculation for 

21 Buildings. It is the base class for all archetype buildings and holds a 

22 list containing all ThermalZones instances. In addition it can hold an 

23 optional attribute for CentralAHU instance, that is e.g. needed for 

24 AixLib Simulation models. 

25 

26 Parameters 

27 ---------- 

28 

29 parent: Project() 

30 The parent class of this object, the Project the Building belongs to. 

31 Allows for better control of hierarchical structures. If not None it 

32 adds this Building instance to Project.buildings. 

33 (default: None) 

34 name : str 

35 Individual name (default: None) 

36 year_of_construction : int 

37 Year of first construction (default: None) 

38 net_leased_area : float [m2] 

39 Total net leased area of building. This is area is NOT the footprint 

40 of a building (default: None) 

41 with_ahu : Boolean 

42 If set to True, an empty instance of BuildingAHU is instantiated and 

43 assigned to attribute central_ahu. This instance holds information for 

44 central Air Handling units. Default is False. 

45 internal_gains_mode: int [1, 2, 3] 

46 mode for the internal gains calculation done in AixLib: 

47 

48 1. Temperature and activity degree dependent heat flux calculation for persons. The 

49 calculation is based on SIA 2024 (default) 

50 2. Temperature and activity degree independent heat flux calculation for persons, the max. 

51 heatflowrate is prescribed by the parameter 

52 fixed_heat_flow_rate_persons. 

53 3. Temperature and activity degree dependent calculation with 

54 consideration of moisture and co2. The moisture calculation is 

55 based on SIA 2024 (2015) and regards persons and non-persons, the co2 calculation is based on 

56 Engineering ToolBox (2004) and regards only persons. 

57 inner_wall_approximation_approach : str 

58 'teaser_default' (default) assumes area of inner wall per room as equal 

59 to one typical length (defined in use conditions) * height of 

60 floors, where number of rooms is 

61 zone area/(typical length + typical width) 

62 'typical_minus_outer' sets length of inner walls per room = 2 * typical 

63 length * height of floors + 2 * typical width * height of floors 

64 - length of outer or interzonal walls. When calculating the number 

65 of rooms, considers the square root of the share for non-complete 

66 rooms in comparison to 'teaser_default'. 

67 'typical_minus_outer_extended' like 'typical_minus_outer', but also 

68 considers that rooftops, windows and ground floors (= walls with 

69 border to soil) may have vertical and horizontal shares 

70 area of floors and ceilings is not affected by this and always equal to 

71 (zone number of floors - 1) * zone area 

72 

73 Attributes 

74 ---------- 

75 central_ahu : instance of BuildingAHU 

76 Teaser Instance of BuildingAHU if a central AHU is embedded into the 

77 building (currently mostly needed for AixLib simulation). 

78 number_of_floors : int 

79 number of floors above ground (default: None) 

80 height_of_floors : float [m] 

81 Average height of the floors (default: None) 

82 internal_id : float 

83 Random id for the distinction between different buildings. 

84 year_of_retrofit : int 

85 Year of last retrofit. 

86 type_of_building : string 

87 Type of a Building (e.g. Building (unspecified), Office etc.). 

88 building_id : None 

89 ID of building, can be set by the user to keep track of a building 

90 even outside of TEASER, e.g. in a simulation or in post-processing. 

91 This is not the same as internal_id, as internal_id is e.g. not 

92 exported to Modelica models! 

93 street_name : string 

94 Name of the street the building is located at. (optional) 

95 city : string 

96 Name of the city the building is located at. (optional) 

97 longitude : float [degree] 

98 Longitude of building location. 

99 latitude : float [degree] 

100 Latitude of building location. 

101 thermal_zones : list 

102 List with instances of ThermalZone(), that are located in this building. 

103 outer_area : dict [degree: m2] 

104 Dictionary with orientation as key and sum of outer wall areas of 

105 that direction as value. 

106 window_area : dict [degree: m2] 

107 Dictionary with orientation as key and sum of window areas of 

108 that direction as value. 

109 bldg_height : float [m] 

110 Total building height. 

111 area_rt : float [m2] 

112 Total roof area of all thermal zones. 

113 area_gf : float [m2] 

114 Total ground floor area of all thermal zones. 

115 volume : float [m3] 

116 Total volume of all thermal zones. 

117 sum_heat_load : float [W] 

118 Total heating load of all thermal zones. 

119 sum_cooling_load : float [W] 

120 Total heating load of all thermal zones. (currently not supported) 

121 number_of_elements_calc : int 

122 Number of elements that are used for thermal zone calculation in this 

123 building. 

124 

125 1. OneElement 

126 2. TwoElement 

127 3. ThreeElement 

128 4. FourElement 

129 

130 merge_windows_calc : boolean 

131 True for merging the windows into the outer wall's RC-combination, 

132 False for separate resistance for window, default is False. (Only 

133 supported for IBPSA) 

134 used_library_calc : str 

135 'AixLib' for https://github.com/RWTH-EBC/AixLib 

136 'IBPSA' for https://github.com/ibpsa/modelica 

137 library_attr : Annex() or AixLib() instance 

138 Classes with specific functions and attributes for building models in 

139 IBPSA and AixLib. Python classes can be found in calculation package. 

140 t_bt : float 

141 Time constant according to VDI 6007. 

142 Default 5 d, only change if you know what you are doing. 

143 See https://publications.rwth-aachen.de/record/749705/files/749705.pdf for more 

144 information (Section 4.1.2) 

145 t_bt_layer: float 

146 Time constant according to VDI 6007 for aggragation of layers. 

147 Default 7 d, only change if you know what you are doing 

148 See https://publications.rwth-aachen.de/record/749705/files/749705.pdf for more 

149 information (Section 4.1.2) 

150 """ 

151 

152 def __init__( 

153 self, 

154 parent=None, 

155 name=None, 

156 year_of_construction=None, 

157 net_leased_area=None, 

158 with_ahu=False, 

159 internal_gains_mode=1, 

160 inner_wall_approximation_approach='teaser_default' 

161 ): 

162 """Constructor of Building Class 

163 """ 

164 

165 self.parent = parent 

166 self.name = name 

167 self.year_of_construction = year_of_construction 

168 self.net_leased_area = net_leased_area 

169 self._with_ahu = with_ahu 

170 

171 if with_ahu is True: 

172 self.central_ahu = BuildingAHU(self) 

173 else: 

174 self._central_ahu = None 

175 

176 self.internal_gains_mode = internal_gains_mode 

177 self.number_of_floors = None 

178 self.height_of_floors = None 

179 self.inner_wall_approximation_approach \ 

180 = inner_wall_approximation_approach 

181 self.internal_id = random.random() 

182 self._year_of_retrofit = None 

183 self.type_of_building = type(self).__name__ 

184 self.building_id = None 

185 self.street_name = "" 

186 self.city = "" 

187 self.longitude = 6.05 

188 self.latitude = 50.79 

189 

190 self._thermal_zones = [] 

191 self._outer_area = {} 

192 self._window_area = {} 

193 

194 self.bldg_height = None 

195 self.area_rt = None 

196 self.area_gf = None 

197 self.volume = 0 

198 self.sum_heat_load = 0 

199 self.sum_cooling_load = 0 

200 self._number_of_elements_calc = 2 

201 self._merge_windows_calc = False 

202 self._used_library_calc = "AixLib" 

203 

204 self.library_attr = None 

205 

206 self.t_bt = 5 

207 self.t_bt_layer = 7 

208 

209 def set_outer_wall_area(self, new_area, orientation): 

210 """Outer area wall setter 

211 

212 sets the outer wall area of all walls of one direction and weights 

213 them according to zone size. This function covers OuterWalls, 

214 Rooftops, GroundFloors. 

215 

216 Parameters 

217 ---------- 

218 new_area : float 

219 new_area of all outer walls of one orientation 

220 orientation : float 

221 orientation of the obtained walls 

222 """ 

223 

224 for zone in self.thermal_zones: 

225 for wall in zone.outer_walls: 

226 if wall.orientation == orientation: 

227 wall.area = ((new_area / self.net_leased_area) * zone.area) / sum( 

228 count.orientation == orientation for count in zone.outer_walls 

229 ) 

230 

231 for roof in zone.rooftops: 

232 if roof.orientation == orientation: 

233 roof.area = ((new_area / self.net_leased_area) * zone.area) / sum( 

234 count.orientation == orientation for count in zone.rooftops 

235 ) 

236 

237 for ground in zone.ground_floors: 

238 if ground.orientation == orientation: 

239 ground.area = ((new_area / self.net_leased_area) * zone.area) / sum( 

240 count.orientation == orientation for count in zone.ground_floors 

241 ) 

242 

243 for door in zone.doors: 

244 if door.orientation == orientation: 

245 door.area = ((new_area / self.net_leased_area) * zone.area) / sum( 

246 count.orientation == orientation for count in zone.doors 

247 ) 

248 

249 def set_window_area(self, new_area, orientation): 

250 """Window area setter 

251 

252 sets the window area of all windows of one direction and weights 

253 them according to zone size 

254 

255 Parameters 

256 ---------- 

257 new_area : float 

258 new_area of all window of one orientation 

259 orientation : float 

260 orientation of the obtained windows 

261 """ 

262 

263 for zone in self.thermal_zones: 

264 for win in zone.windows: 

265 if win.orientation == orientation: 

266 win.area = ((new_area / self.net_leased_area) * zone.area) / sum( 

267 count.orientation == orientation for count in zone.windows 

268 ) 

269 

270 def get_outer_wall_area(self, orientation): 

271 """Get aggregated wall area of one orientation 

272 

273 Returns the area of all outer walls of one direction. This function 

274 covers OuterWalls, GroundFloors and Rooftops. 

275 

276 Parameters 

277 ---------- 

278 orientation : float 

279 orientation of the obtained wall 

280 Returns 

281 ------- 

282 sum_area : float 

283 area of all walls of one direction 

284 """ 

285 

286 sum_area = 0.0 

287 for zone_count in self.thermal_zones: 

288 for wall_count in zone_count.outer_walls: 

289 if ( 

290 wall_count.orientation == orientation 

291 and wall_count.area is not None 

292 ): 

293 sum_area += wall_count.area 

294 for roof_count in zone_count.rooftops: 

295 if ( 

296 roof_count.orientation == orientation 

297 and roof_count.area is not None 

298 ): 

299 sum_area += roof_count.area 

300 for ground_count in zone_count.ground_floors: 

301 if ( 

302 ground_count.orientation == orientation 

303 and ground_count.area is not None 

304 ): 

305 sum_area += ground_count.area 

306 return sum_area 

307 

308 def get_window_area(self, orientation): 

309 """Get aggregated window area of one orientation 

310 

311 returns the area of all windows of one direction 

312 

313 Parameters 

314 ---------- 

315 orientation : float 

316 orientation of the obtained windows 

317 Returns 

318 ------- 

319 sum_area : float 

320 area of all windows of one direction 

321 """ 

322 

323 sum_area = 0.0 

324 for zone_count in self.thermal_zones: 

325 for win_count in zone_count.windows: 

326 if win_count.orientation == orientation and win_count.area is not None: 

327 sum_area += win_count.area 

328 return sum_area 

329 

330 def get_inner_wall_area(self): 

331 """Get aggregated inner wall area 

332 

333 Returns the area of all inner walls. This function covers InnerWalls, 

334 Ceilings and Floors. 

335 

336 Returns 

337 ------- 

338 sum_area : float 

339 area of all inner walls 

340 

341 """ 

342 

343 sum_area = 0.0 

344 for zone_count in self.thermal_zones: 

345 for wall_count in zone_count.inner_walls: 

346 sum_area += wall_count.area 

347 for floor in zone_count.floors: 

348 sum_area += floor.area 

349 for ceiling in zone_count.ceilings: 

350 sum_area += ceiling.area 

351 return sum_area 

352 

353 def fill_outer_area_dict(self): 

354 """Fills the attribute outer_area 

355 

356 Fills the dictionary outer_area with the sum of outer wall area 

357 corresponding to the orientations of the building. This function 

358 covers OuterWalls, GroundFloors and Rooftops. 

359 

360 """ 

361 self.outer_area = {} 

362 for zone_count in self.thermal_zones: 

363 for wall_count in zone_count.outer_walls: 

364 self.outer_area[wall_count.orientation] = None 

365 for roof in zone_count.rooftops: 

366 self.outer_area[roof.orientation] = None 

367 for ground in zone_count.ground_floors: 

368 self.outer_area[ground.orientation] = None 

369 

370 for key in self.outer_area: 

371 self.outer_area[key] = self.get_outer_wall_area(key) 

372 

373 def fill_window_area_dict(self): 

374 """Fills the attribute 

375 

376 Fills the dictionary window_area with the sum of window area 

377 corresponding to the orientations of the building. 

378 

379 """ 

380 self.window_area = {} 

381 for zone_count in self.thermal_zones: 

382 for win_count in zone_count.windows: 

383 self.window_area[win_count.orientation] = None 

384 

385 for key in self.window_area: 

386 self.window_area[key] = self.get_window_area(key) 

387 

388 def calc_building_parameter( 

389 self, 

390 number_of_elements=None, 

391 merge_windows=None, 

392 used_library=None 

393 ): 

394 """calc all building parameters 

395 

396 This functions calculates the parameters of all zones in a building 

397 sums norm heat load of all zones 

398 sums volume of all zones 

399 

400 Parameters 

401 ---------- 

402 number_of_elements : int, optional 

403 defines the number of elements, that area aggregated, between 1 

404 and 5. Default is 2. If None, uses existing class property 

405 merge_windows : bool, optional 

406 True for merging the windows into the outer walls, False for 

407 separate resistance for window. If None, uses existing class 

408 property 

409 used_library : str, optional 

410 used library (AixLib and IBPSA are supported). If None, uses 

411 existing class property 

412 """ 

413 # Use provided values or fall back to existing class properties 

414 number_of_elements = ( 

415 number_of_elements if number_of_elements is not None 

416 else self._number_of_elements_calc) 

417 merge_windows = (merge_windows if merge_windows is not None 

418 else self._merge_windows_calc) 

419 used_library = used_library if used_library is not None else ( 

420 self._used_library_calc) 

421 

422 # Update class properties with the values being used 

423 self.number_of_elements_calc = number_of_elements 

424 self.merge_windows_calc = merge_windows 

425 self.used_library_calc = used_library 

426 

427 self.area_rt = 0 

428 self.area_gf = 0 

429 for zone in self.thermal_zones: 

430 zone.calc_zone_parameters( 

431 number_of_elements=number_of_elements, 

432 merge_windows=merge_windows, 

433 t_bt=self.t_bt, 

434 t_bt_layer=self.t_bt_layer 

435 ) 

436 self.sum_heat_load += zone.model_attr.heat_load 

437 self.area_rt += sum(rf.area for rf in zone.rooftops) 

438 self.area_gf += sum(gf.area for gf in zone.ground_floors) 

439 

440 if self.used_library_calc == self.library_attr.__class__.__name__: 

441 if self.used_library_calc == "AixLib": 

442 self.library_attr.calc_auxiliary_attr() 

443 else: 

444 pass 

445 elif self.library_attr is None: 

446 if self.used_library_calc == "AixLib": 

447 self.library_attr = AixLib(parent=self) 

448 self.library_attr.calc_auxiliary_attr() 

449 elif self.used_library_calc == "IBPSA": 

450 self.library_attr = IBPSA(parent=self) 

451 else: 

452 warnings.warn( 

453 "You set conflicting options for the used library " 

454 "in Building or Project class and " 

455 "calculation function of building. Your library " 

456 "attributes are set to default using the library " 

457 "you indicated in the function call, which is: " 

458 + self.used_library_calc 

459 ) 

460 

461 if self.used_library_calc == "AixLib": 

462 self.library_attr = AixLib(parent=self) 

463 self.library_attr.calc_auxiliary_attr() 

464 elif self.used_library_calc == "IBPSA": 

465 self.library_attr = IBPSA(parent=self) 

466 

467 def retrofit_building( 

468 self, 

469 year_of_retrofit=None, 

470 type_of_retrofit=None, 

471 window_type=None, 

472 material=None, 

473 ): 

474 """Retrofits all zones in the building 

475 

476 Function call for each zone. 

477 

478 After retrofit, all parameters are calculated directly. 

479 

480 Parameters 

481 ---------- 

482 year_of_retrofit : float 

483 Year of last retrofit. 

484 type_of_retrofit : str 

485 The classification of retrofit, if the archetype building 

486 approach of TABULA is used. 

487 window_type : str 

488 Default: EnEv 2014 

489 material : str 

490 Default: EPS035 

491 """ 

492 

493 # Set self.sum_heat_load to zero to prevent summing up of old and new 

494 # design heat load calculation values (see #518) 

495 self.sum_heat_load = 0 

496 

497 if year_of_retrofit is not None: 

498 self.year_of_retrofit = year_of_retrofit 

499 

500 for zone in self.thermal_zones: 

501 zone.retrofit_zone(type_of_retrofit, window_type, material) 

502 

503 self.calc_building_parameter( 

504 number_of_elements=self.number_of_elements_calc, 

505 merge_windows=self.merge_windows_calc, 

506 used_library=self.used_library_calc, 

507 ) 

508 

509 def rotate_building(self, angle): 

510 """Rotates the building to a given angle 

511 

512 This function covers OuterWall, Rooftop (if not flat roof) and Windows. 

513 

514 Parameters 

515 ---------- 

516 

517 angle: float 

518 rotation of the building clockwise, between 0 and 360 degrees 

519 """ 

520 

521 for zone_count in self.thermal_zones: 

522 new_angle = None 

523 for wall_count in zone_count.outer_walls: 

524 new_angle = wall_count.orientation + angle 

525 if new_angle > 360.0: 

526 wall_count.orientation = new_angle - 360.0 

527 else: 

528 wall_count.orientation = new_angle 

529 for roof_count in zone_count.rooftops: 

530 if roof_count.orientation != -1: 

531 new_angle = roof_count.orientation + angle 

532 if new_angle > 360.0: 

533 roof_count.orientation = new_angle - 360.0 

534 else: 

535 roof_count.orientation = new_angle 

536 else: 

537 pass 

538 for win_count in zone_count.windows: 

539 new_angle = win_count.orientation + angle 

540 if new_angle > 360.0: 

541 win_count.orientation = new_angle - 360.0 

542 else: 

543 win_count.orientation = new_angle 

544 

545 def add_zone(self, thermal_zone): 

546 """Adds a thermal zone to the corresponding list 

547 

548 This function adds a ThermalZone instance to the the thermal_zones list 

549 

550 Parameters 

551 ---------- 

552 thermal_zone : ThermalZone() 

553 ThermalZone() instance of TEASER 

554 """ 

555 

556 ass_error_1 = "Zone has to be an instance of ThermalZone()" 

557 

558 assert type(thermal_zone).__name__ == "ThermalZone", ass_error_1 

559 

560 self._thermal_zones.append(thermal_zone) 

561 

562 @property 

563 def parent(self): 

564 return self.__parent 

565 

566 @parent.setter 

567 def parent(self, value): 

568 

569 if value is not None: 

570 

571 ass_error_1 = "Parent has to be an instance of Project()" 

572 

573 assert type(value).__name__ == "Project", ass_error_1 

574 

575 self.__parent = value 

576 

577 if inspect.isclass(Building): 

578 if self in self.__parent.buildings: 

579 pass 

580 else: 

581 self.__parent.buildings.append(self) 

582 

583 else: 

584 

585 self.__parent = None 

586 

587 @property 

588 def name(self): 

589 return self.__name 

590 

591 @name.setter 

592 def name(self, value): 

593 if isinstance(value, str): 

594 regex = re.compile("[^a-zA-z0-9]") 

595 self.__name = regex.sub("", value) 

596 else: 

597 try: 

598 value = str(value) 

599 regex = re.compile("[^a-zA-z0-9]") 

600 self.__name = regex.sub("", value) 

601 except ValueError: 

602 print("Can't convert name to string") 

603 

604 if self.__name[0].isdigit(): 

605 self.__name = "B" + self.__name 

606 

607 @property 

608 def year_of_construction(self): 

609 return self.__year_of_construction 

610 

611 @year_of_construction.setter 

612 def year_of_construction(self, value): 

613 

614 if isinstance(value, int) or value is None: 

615 

616 self.__year_of_construction = value 

617 else: 

618 try: 

619 value = int(value) 

620 self.__year_of_construction = value 

621 

622 except: 

623 raise ValueError("Can't convert year of construction to int") 

624 

625 @property 

626 def number_of_floors(self): 

627 return self.__number_of_floors 

628 

629 @number_of_floors.setter 

630 def number_of_floors(self, value): 

631 

632 if isinstance(value, int) or value is None: 

633 

634 self.__number_of_floors = value 

635 else: 

636 try: 

637 value = int(value) 

638 self.__number_of_floors = value 

639 

640 except: 

641 raise ValueError("Can't convert number of floors to int") 

642 

643 @property 

644 def height_of_floors(self): 

645 return self.__height_of_floors 

646 

647 @height_of_floors.setter 

648 def height_of_floors(self, value): 

649 

650 if isinstance(value, float) or value is None: 

651 

652 self.__height_of_floors = value 

653 else: 

654 try: 

655 value = float(value) 

656 self.__height_of_floors = value 

657 

658 except: 

659 raise ValueError("Can't convert height of floors to float") 

660 

661 @property 

662 def net_leased_area(self): 

663 return self.__net_leased_area 

664 

665 @net_leased_area.setter 

666 def net_leased_area(self, value): 

667 

668 if isinstance(value, float): 

669 self.__net_leased_area = value 

670 elif value is None: 

671 self.__net_leased_area = value 

672 else: 

673 try: 

674 value = float(value) 

675 self.__net_leased_area = value 

676 except: 

677 raise ValueError("Can't convert net leased area to float") 

678 

679 @property 

680 def thermal_zones(self): 

681 return self._thermal_zones 

682 

683 @thermal_zones.setter 

684 def thermal_zones(self, value): 

685 

686 if value is None: 

687 self._thermal_zones = [] 

688 

689 @property 

690 def outer_area(self): 

691 return self._outer_area 

692 

693 @outer_area.setter 

694 def outer_area(self, value): 

695 self._outer_area = value 

696 

697 @property 

698 def window_area(self): 

699 return self._window_area 

700 

701 @window_area.setter 

702 def window_area(self, value): 

703 self._window_area = value 

704 

705 @property 

706 def year_of_retrofit(self): 

707 return self._year_of_retrofit 

708 

709 @year_of_retrofit.setter 

710 def year_of_retrofit(self, value): 

711 if self.year_of_construction is not None: 

712 self._year_of_retrofit = value 

713 else: 

714 raise ValueError("Specify year of construction first") 

715 

716 @property 

717 def with_ahu(self): 

718 return self._with_ahu 

719 

720 @with_ahu.setter 

721 def with_ahu(self, value): 

722 

723 if value is True and self.central_ahu is None: 

724 self.central_ahu = BuildingAHU(self) 

725 self._with_ahu = True 

726 elif value and self.central_ahu and self._with_ahu is False: 

727 self._with_ahu = True 

728 elif value is False and self.central_ahu: 

729 self.central_ahu = None 

730 self._with_ahu = False 

731 

732 @property 

733 def central_ahu(self): 

734 return self._central_ahu 

735 

736 @central_ahu.setter 

737 def central_ahu(self, value): 

738 

739 if value is None: 

740 self._central_ahu = value 

741 else: 

742 

743 ass_error_1 = "central AHU has to be an instance of BuildingAHU()" 

744 

745 assert type(value).__name__ == "BuildingAHU", ass_error_1 

746 

747 self._central_ahu = value 

748 

749 @property 

750 def number_of_elements_calc(self): 

751 

752 return self._number_of_elements_calc 

753 

754 @number_of_elements_calc.setter 

755 def number_of_elements_calc(self, value): 

756 

757 ass_error_1 = "calculation_method has to be 1, 2, 3, 4, or 5" 

758 

759 assert value != [1, 2, 3, 4, 5], ass_error_1 

760 

761 if self.parent is None and value is None: 

762 self._number_of_elements_calc = 2 

763 elif self.parent is not None and value is None: 

764 self._number_of_elements_calc = self.parent.number_of_elements_calc 

765 elif value is not None: 

766 self._number_of_elements_calc = value 

767 

768 @property 

769 def merge_windows_calc(self): 

770 

771 return self._merge_windows_calc 

772 

773 @merge_windows_calc.setter 

774 def merge_windows_calc(self, value): 

775 

776 ass_error_1 = "merge windows needs to be True or False" 

777 

778 assert value != [True, False], ass_error_1 

779 

780 if self.parent is None and value is None: 

781 self._merge_windows_calc = 2 

782 elif self.parent is not None and value is None: 

783 self._merge_windows_calc = self.parent.merge_windows_calc 

784 elif value is not None: 

785 self._merge_windows_calc = value 

786 

787 @property 

788 def used_library_calc(self): 

789 

790 return self._used_library_calc 

791 

792 @used_library_calc.setter 

793 def used_library_calc(self, value): 

794 

795 ass_error_1 = "used library needs to be AixLib or IBPSA" 

796 

797 assert value != ["AixLib", "IBPSA"], ass_error_1 

798 

799 if self.parent is None and value is None: 

800 self._used_library_calc = "AixLib" 

801 elif self.parent is not None and value is None: 

802 self._used_library_calc = self.parent.used_library_calc 

803 elif value is not None: 

804 self._used_library_calc = value 

805 

806 if self.used_library_calc == "AixLib": 

807 self.library_attr = AixLib(parent=self) 

808 elif self.used_library_calc == "IBPSA": 

809 self.library_attr = IBPSA(parent=self) 

810 

811 @property 

812 def inner_wall_approximation_approach(self): 

813 return self._inner_wall_approximation_approach 

814 

815 @inner_wall_approximation_approach.setter 

816 def inner_wall_approximation_approach(self, value): 

817 ass_error_1 = "inner wall approximation approach needs to be one of " \ 

818 "'teaser_default', 'typical_minus_outer', "\ 

819 "'typical_minus_outer_extended'" 

820 

821 assert value in ( 

822 'teaser_default', 

823 'typical_minus_outer', 

824 'typical_minus_outer_extended' 

825 ), ass_error_1 

826 

827 self._inner_wall_approximation_approach = value