Coverage for teaser/logic/archetypebuildings/bmvbs/singlefamilydwelling.py: 98%

245 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 

4from teaser.logic.archetypebuildings.residential import Residential 

5from teaser.logic.buildingobjects.useconditions import UseConditions as UseCond 

6from teaser.logic.buildingobjects.buildingphysics.ceiling import Ceiling 

7from teaser.logic.buildingobjects.buildingphysics.floor import Floor 

8from teaser.logic.buildingobjects.buildingphysics.groundfloor import GroundFloor 

9from teaser.logic.buildingobjects.buildingphysics.innerwall import InnerWall 

10from teaser.logic.buildingobjects.buildingphysics.outerwall import OuterWall 

11from teaser.logic.buildingobjects.buildingphysics.rooftop import Rooftop 

12from teaser.logic.buildingobjects.buildingphysics.window import Window 

13from teaser.logic.buildingobjects.thermalzone import ThermalZone 

14import teaser.data.utilities as datahandling 

15 

16class SingleFamilyDwelling(Residential): 

17 """Archetype Residential Building according 

18 

19 Subclass from Residential archetype class to represent 

20 SingleFamilyDwelling according to IWU :cite:`KurzverfahrenIWU`. 

21 

22 The SingleFamilyDwelling module contains a single zone building. It has 4 

23 outer walls, 4 windows, a flat roof and a ground floor. Interior wall 

24 areas are assigned related to typical width and depth of zones according to 

25 :cite:`SwissSocietyofEngineersandArchitects.March2006`. It makes 

26 number_of_floors and height_of_floors mandatory parameters. 

27 Additional information can be passed 

28 to the archetype (e.g. floor layout and number of neighbors). 

29 

30 Default values are given according to IWU. 

31 

32 In detail the net leased area is divided into the following thermal zone 

33 area: 

34 

35 #. Single dwelling (100% of net leased area) 

36 

37 Parameters 

38 ---------- 

39 

40 parent: Project() 

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

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

43 adds this Building instance to Project.buildings. 

44 (default: None) 

45 name : str 

46 Individual name 

47 year_of_construction : int 

48 Year of first construction 

49 height_of_floors : float [m] 

50 Average height of the buildings' floors 

51 number_of_floors : int 

52 Number of building's floors above ground 

53 net_leased_area : float [m2] 

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

55 of a building 

56 with_ahu : Boolean 

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

58 assigned to attribute central_ahu. This instance holds information for 

59 central Air Handling units. Default is False. 

60 internal_gains_mode: int [1, 2, 3] 

61 mode for the internal gains calculation done in AixLib: 

62 

63 1. Temperature and activity degree dependent heat flux calculation. The 

64 calculation is based on SIA 2024 (default) 

65 2. Temperature and activity degree independent heat flux calculation, the max. 

66 heatflowrate is prescribed by the parameter 

67 fixed_heat_flow_rate_persons. 

68 3. Temperature and activity degree dependent calculation with 

69 consideration of moisture and co2. The moisture calculation is 

70 based on SIA 2024 (2015), the co2 calculation is based on 

71 Engineering ToolBox (2004) 

72 inner_wall_approximation_approach : str 

73 'teaser_default' (default) sets length of inner walls = typical 

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

75 'typical_minus_outer' sets length of inner walls = 2 * typical 

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

77 - length of outer or interzonal walls 

78 'typical_minus_outer_extended' like 'typical_minus_outer', but also 

79 considers that 

80 a) a non-complete "average room" reduces its circumference 

81 proportional to the square root of the area 

82 b) rooftops, windows and ground floors (= walls with border to 

83 soil) may have a vertical share 

84 residential_layout : int 

85 Structure of floor plan (default = 0) 

86 

87 0. compact 

88 1. elongated/complex 

89 

90 neighbour_buildings : int 

91 Number of neighbour buildings. CAUTION: this will not change 

92 the orientation of the buildings wall, but just the overall 

93 exterior wall and window area(!) (default = 0) 

94 

95 0. no neighbour 

96 1. one neighbour 

97 2. two neighbours 

98 

99 attic : int 

100 Design of the attic. CAUTION: this will not change the orientation or 

101 tilt of the roof instances, but just adapt the roof area(!) (default 

102 = 0) 

103 

104 0. flat roof 

105 1. non heated attic 

106 2. partly heated attic 

107 3. heated attic 

108 

109 cellar : int 

110 Design of the of cellar CAUTION: this will not change the 

111 orientation, tilt of GroundFloor instances, nor the number or area of 

112 ThermalZones, but will change GroundFloor area(!) (default = 0) 

113 

114 0. no cellar 

115 1. non heated cellar 

116 2. partly heated cellar 

117 3. heated cellar 

118 

119 dormer : str 

120 Is a dormer attached to the roof? CAUTION: this will not 

121 change roof or window orientation or tilt, but just adapt the roof 

122 area(!) (default = 0) 

123 

124 0. no dormer 

125 1. dormer 

126 

127 construction_data : str 

128 Construction type of used wall constructions default is "iwu_heavy" 

129 

130 - iwu_heavy: heavy construction 

131 - iwu_light: light construction 

132 - kfw_40, kfw_55, kfw_70, kfw_85, kfw_100: KfW efficiency building standards 

133 

134 Notes 

135 ----- 

136 The listed attributes are just the ones that are set by the user 

137 calculated values are not included in this list. Changing these values is 

138 expert mode. 

139 

140 

141 Attributes 

142 ---------- 

143 

144 zone_area_factors : dict 

145 This dictionary contains the name of the zone (str), the 

146 zone area factor (float), the zone usage from BoundaryConditions json 

147 (str) (Default see doc string above), and may contain a dictionary with 

148 keyword-attribute-like changes to zone parameters that are usually 

149 inherited from parent: 'number_of_floors', 'height_of_floors' 

150 outer_wall_names : dict 

151 This dictionary contains a random name for the outer walls, 

152 their orientation and tilt. Default is a building in north-south 

153 orientation) 

154 roof_names : dict 

155 This dictionary contains the name of the roofs, their orientation 

156 and tilt. Default is one flat roof. 

157 ground_floor_names : dict 

158 This dictionary contains the name of the ground floors, their 

159 orientation and tilt. Default is one ground floor. 

160 window_names : dict 

161 This dictionary contains the name of the window, their 

162 orientation and tilt. Default is a building in north-south 

163 orientation) 

164 inner_wall_names : dict 

165 This dictionary contains the name of the inner walls, their 

166 orientation and tilt. Default is one cumulated inner wall. 

167 ceiling_names : dict 

168 This dictionary contains the name of the ceilings, their 

169 orientation and tilt. Default is one cumulated ceiling. 

170 floor_names : dict 

171 This dictionary contains the name of the floors, their 

172 orientation and tilt. Default is one cumulated floor. 

173 est_living_area_factor : float 

174 Estimation factor for calculation of number of heated floors 

175 est_bottom_building_closure : float 

176 Estimation factor to calculate ground floor area 

177 est_upper_building_closure : float 

178 Estimation factor to calculate attic area 

179 est_factor_win_area : float 

180 Estimation factor to calculate window area 

181 est_factor_cellar_area : float 

182 Estimation factor to calculate heated cellar area 

183 """ 

184 

185 def __init__( 

186 self, 

187 parent, 

188 name=None, 

189 year_of_construction=None, 

190 number_of_floors=None, 

191 height_of_floors=None, 

192 net_leased_area=None, 

193 with_ahu=False, 

194 inner_wall_approximation_approach='teaser_default', 

195 internal_gains_mode=1, 

196 residential_layout=None, 

197 neighbour_buildings=None, 

198 attic=None, 

199 cellar=None, 

200 dormer=None, 

201 construction_data=None, 

202 ): 

203 """Constructor of SingleFamilyDwelling 

204 """ 

205 

206 super(SingleFamilyDwelling, self).__init__( 

207 parent, 

208 name, 

209 year_of_construction, 

210 net_leased_area, 

211 with_ahu, 

212 internal_gains_mode, 

213 inner_wall_approximation_approach 

214 ) 

215 

216 self.residential_layout = residential_layout 

217 self.neighbour_buildings = neighbour_buildings 

218 self.attic = attic 

219 self.cellar = cellar 

220 self.dormer = dormer 

221 self.construction_data = construction_data 

222 self.number_of_floors = number_of_floors 

223 self.height_of_floors = height_of_floors 

224 

225 # Parameters are default values for current calculation following IWU 

226 

227 # [area factor, usage type(has to be set)] 

228 self.zone_area_factors = {"SingleDwelling": [1, "Living"]} 

229 

230 self.outer_wall_names = { 

231 "Exterior Facade North": [90.0, 0.0], 

232 "Exterior Facade East": [90.0, 90.0], 

233 "Exterior Facade South": [90.0, 180.0], 

234 "Exterior Facade West": [90.0, 270.0], 

235 } 

236 # [tilt, orientation] 

237 

238 self.roof_names = {"Rooftop": [0, -1]} # [0, -1] 

239 

240 self.ground_floor_names = {"Ground Floor": [0, -2]} # [0, -2] 

241 

242 self.window_names = { 

243 "Window Facade North": [90.0, 0.0], 

244 "Window Facade East": [90.0, 90.0], 

245 "Window Facade South": [90.0, 180.0], 

246 "Window Facade West": [90.0, 270.0], 

247 } 

248 # [tilt, orientation] 

249 

250 self.inner_wall_names = {"InnerWall": [90.0, 0.0]} 

251 

252 self.ceiling_names = {"Ceiling": [0.0, -1]} 

253 

254 self.floor_names = {"Floor": [0.0, -2]} 

255 

256 self.est_living_area_factor = 0.75 # fW 

257 self.est_bottom_building_closure = 1.33 # p_FB 

258 self.est_upper_building_closure = 1.0 

259 self.est_factor_win_area = 0.2 

260 self.est_factor_cellar_area = 0.5 

261 

262 self.nr_of_orientation = len(self.outer_wall_names) 

263 

264 # estimated intermediate calculated values 

265 self._living_area_per_floor = 0 

266 self._number_of_heated_floors = 0 

267 self._est_factor_heated_cellar = 0 

268 self._est_factor_heated_attic = 0 

269 self._est_roof_area = 0 

270 self._est_ground_floor_area = 0.0 

271 self._est_win_area = 0 

272 self._est_outer_wall_area = 0.0 

273 self._est_cellar_wall_area = 0 

274 self._est_factor_volume = 0.0 

275 

276 self.est_factor_neighbour = 0.0 # n_Nachbar 

277 self.est_extra_floor_area = 0.0 # q_Fa 

278 

279 if self.neighbour_buildings == 0: 

280 self._est_factor_neighbour = 0.0 

281 self._est_extra_floor_area = 50.0 

282 elif self.neighbour_buildings == 1: 

283 self._est_factor_neighbour = 1.0 

284 self._est_extra_floor_area = 30.0 

285 elif self.neighbour_buildings == 2: 

286 self._est_factor_neighbour = 2.0 

287 self._est_extra_floor_area = 10.0 

288 

289 self._est_facade_to_floor_area = 0.0 # p_Fa 

290 

291 if self.residential_layout == 0: 

292 self._est_facade_to_floor_area = 0.66 

293 elif self.residential_layout == 1: 

294 self._est_facade_to_floor_area = 0.8 

295 

296 self._est_factor_heated_attic = 0.0 # f_TB_DG 

297 self._est_area_per_floor = 0.0 # p_DA 

298 self._est_area_per_roof = 0.0 # p_OG 

299 

300 if self.attic == 0: 

301 self._est_factor_heated_attic = 0.0 

302 self._est_area_per_floor = 1.33 

303 self._est_area_per_roof = 0.0 

304 elif self.attic == 1: 

305 self._est_factor_heated_attic = 0.0 

306 self._est_area_per_floor = 0.0 

307 self._est_area_per_roof = 1.33 

308 elif self.attic == 2: 

309 self._est_factor_heated_attic = 0.5 

310 self._est_area_per_floor = 0.75 

311 self._est_area_per_roof = 0.67 

312 elif self.attic == 3: 

313 self._est_factor_heated_attic = 1.0 

314 self._est_area_per_floor = 1.5 

315 self._est_area_per_roof = 0.0 

316 

317 self._est_factor_heated_cellar = 0.0 # f_TB_KG 

318 

319 if self.cellar == 0: 

320 self._est_factor_heated_cellar = 0.0 

321 elif self.cellar == 1: 

322 self._est_factor_heated_cellar = 0.0 

323 elif self.cellar == 2: 

324 self._est_factor_heated_cellar = 0.5 

325 elif self.cellar == 3: 

326 self._est_factor_heated_cellar = 1.0 

327 

328 self._est_factor_dormer = 0.0 

329 

330 if self.dormer == 0: 

331 self._est_factor_dormer = 1.0 

332 elif self.dormer == 1: 

333 self._est_factor_dormer = 1.3 

334 

335 if self.with_ahu is True: 

336 self.central_ahu.temperature_profile = ( 

337 7 * [293.15] + 12 * [295.15] + 5 * [293.15] 

338 ) 

339 # according to :cite:`DeutschesInstitutfurNormung.2016` 

340 self.central_ahu.min_relative_humidity_profile = 24 * [0.45] 

341 # according to :cite:`DeutschesInstitutfurNormung.2016b` and 

342 # :cite:`DeutschesInstitutfurNormung.2016` 

343 self.central_ahu.max_relative_humidity_profile = 24 * [0.65] 

344 self.central_ahu.v_flow_profile = ( 

345 7 * [0.0] + 12 * [1.0] + 5 * [0.0] 

346 ) # according to user # 

347 # profile in :cite:`DeutschesInstitutfurNormung.2016` 

348 

349 def generate_archetype(self): 

350 """Generates a SingleFamilyDwelling building. 

351 

352 With given values, this class generates a archetype building for 

353 single family dwellings according to TEASER requirements 

354 """ 

355 # help area for the correct building area setting while using typeBldgs 

356 self.thermal_zones = None 

357 type_bldg_area = self.net_leased_area 

358 self.net_leased_area = 0.0 

359 

360 self._number_of_heated_floors = ( 

361 self._est_factor_heated_cellar 

362 + self.number_of_floors 

363 + self.est_living_area_factor * self._est_factor_heated_attic 

364 ) 

365 

366 self._living_area_per_floor = type_bldg_area / self._number_of_heated_floors 

367 

368 self._est_ground_floor_area = ( 

369 self.est_bottom_building_closure * self._living_area_per_floor 

370 ) 

371 

372 self._est_roof_area = ( 

373 self.est_upper_building_closure 

374 * self._est_factor_dormer 

375 * self._est_area_per_floor 

376 * self._living_area_per_floor 

377 ) 

378 

379 self._top_floor_area = self._est_area_per_roof * self._living_area_per_floor 

380 

381 if self._est_roof_area == 0: 

382 self._est_roof_area = self._top_floor_area 

383 

384 self._est_facade_area = self._est_facade_to_floor_area * ( 

385 self._living_area_per_floor + self._est_extra_floor_area 

386 ) 

387 

388 self._est_win_area = self.est_factor_win_area * type_bldg_area 

389 

390 self._est_cellar_wall_area = ( 

391 self.est_factor_cellar_area 

392 * self._est_factor_heated_cellar 

393 * self._est_facade_area 

394 ) 

395 

396 self._est_outer_wall_area = ( 

397 (self._number_of_heated_floors * self._est_facade_area) 

398 - self._est_cellar_wall_area 

399 - self._est_win_area 

400 ) 

401 

402 # self._est_factor_volume = type_bldg_area * 2.5 

403 

404 for key, value in self.zone_area_factors.items(): 

405 zone = ThermalZone(self) 

406 zone.name = key 

407 zone.area = type_bldg_area * value[0] 

408 try: 

409 zone.number_of_floors = value[2]['number_of_floors'] 

410 except (KeyError, IndexError): 

411 pass 

412 try: 

413 zone.height_of_floors = value[2]['height_of_floors'] 

414 except (KeyError, IndexError): 

415 pass 

416 use_cond = UseCond(zone) 

417 use_cond.load_use_conditions(value[1], data_class=self.parent.data) 

418 

419 zone.use_conditions = use_cond 

420 zone.use_conditions.with_ahu = False 

421 

422 for key, value in self.outer_wall_names.items(): 

423 # North and South 

424 

425 if value[1] == 0 or value[1] == 180.0: 

426 self.outer_area[value[1]] = ( 

427 self._est_outer_wall_area / self.nr_of_orientation 

428 ) 

429 # East and West 

430 elif value[1] == 90 or value[1] == 270: 

431 

432 self.outer_area[value[1]] = ( 

433 self._est_outer_wall_area / self.nr_of_orientation 

434 ) 

435 

436 for zone in self.thermal_zones: 

437 # create wall and set building elements 

438 outer_wall = OuterWall(zone) 

439 outer_wall.load_type_element( 

440 year=self.year_of_construction, 

441 construction=self.construction_data.value, 

442 data_class=self.parent.data, 

443 ) 

444 outer_wall.name = key 

445 outer_wall.tilt = value[0] 

446 outer_wall.orientation = value[1] 

447 

448 for key, value in self.window_names.items(): 

449 

450 if value[1] == 0 or value[1] == 180: 

451 

452 self.window_area[value[1]] = self._est_win_area / self.nr_of_orientation 

453 

454 elif value[1] == 90 or value[1] == 270: 

455 

456 self.window_area[value[1]] = self._est_win_area / self.nr_of_orientation 

457 

458 """ 

459 There is no real classification for windows, so this is a bit hard 

460 code - will be fixed sometime 

461 """ 

462 for zone in self.thermal_zones: 

463 window = Window(zone) 

464 construction = ( 

465 "Waermeschutzverglasung, dreifach" 

466 if self.construction_data.is_kfw() 

467 else "Kunststofffenster, " "Isolierverglasung" 

468 ) 

469 window.load_type_element( 

470 self.year_of_construction, 

471 construction=construction, 

472 data_class=self.parent.data, 

473 ) 

474 window.name = key 

475 window.tilt = value[0] 

476 window.orientation = value[1] 

477 

478 for key, value in self.roof_names.items(): 

479 

480 self.outer_area[value[1]] = self._est_roof_area 

481 

482 for zone in self.thermal_zones: 

483 roof = Rooftop(zone) 

484 roof.load_type_element( 

485 year=self.year_of_construction, 

486 construction=self.construction_data.value, 

487 data_class=self.parent.data, 

488 ) 

489 roof.name = key 

490 roof.tilt = value[0] 

491 roof.orientation = value[1] 

492 

493 for key, value in self.ground_floor_names.items(): 

494 

495 self.outer_area[value[1]] = self._est_ground_floor_area 

496 

497 for zone in self.thermal_zones: 

498 ground_floor = GroundFloor(zone) 

499 ground_floor.load_type_element( 

500 year=self.year_of_construction, 

501 construction=self.construction_data.value, 

502 data_class=self.parent.data, 

503 ) 

504 ground_floor.name = key 

505 ground_floor.tilt = value[0] 

506 ground_floor.orientation = value[1] 

507 

508 for key, value in self.inner_wall_names.items(): 

509 

510 for zone in self.thermal_zones: 

511 inner_wall = InnerWall(zone) 

512 inner_wall.load_type_element( 

513 year=self.year_of_construction, 

514 construction=self.construction_data.value, 

515 data_class=self.parent.data, 

516 ) 

517 inner_wall.name = key 

518 inner_wall.tilt = value[0] 

519 inner_wall.orientation = value[1] 

520 # zone.inner_walls.append(inner_wall) 

521 

522 if self.number_of_floors > 1: 

523 

524 for key, value in self.ceiling_names.items(): 

525 

526 for zone in self.thermal_zones: 

527 ceiling = Ceiling(zone) 

528 ceiling.load_type_element( 

529 year=self.year_of_construction, 

530 construction=self.construction_data.value, 

531 data_class=self.parent.data, 

532 ) 

533 ceiling.name = key 

534 ceiling.tilt = value[0] 

535 ceiling.orientation = value[1] 

536 # zone.inner_walls.append(ceiling) 

537 

538 for key, value in self.floor_names.items(): 

539 

540 for zone in self.thermal_zones: 

541 floor = Floor(zone) 

542 floor.load_type_element( 

543 year=self.year_of_construction, 

544 construction=self.construction_data.value, 

545 data_class=self.parent.data, 

546 ) 

547 floor.name = key 

548 floor.tilt = value[0] 

549 floor.orientation = value[1] 

550 # zone.inner_walls.append(floor) 

551 else: 

552 pass 

553 

554 for key, value in self.outer_area.items(): 

555 self.set_outer_wall_area(value, key) 

556 for key, value in self.window_area.items(): 

557 self.set_window_area(value, key) 

558 

559 for zone in self.thermal_zones: 

560 zone.set_inner_wall_area() 

561 zone.set_volume_zone() 

562 

563 @property 

564 def residential_layout(self): 

565 return self._residential_layout 

566 

567 @residential_layout.setter 

568 def residential_layout(self, value): 

569 if value is not None: 

570 self._residential_layout = value 

571 else: 

572 self._residential_layout = 0 

573 

574 @property 

575 def neighbour_buildings(self): 

576 return self._neighbour_buildings 

577 

578 @neighbour_buildings.setter 

579 def neighbour_buildings(self, value): 

580 if value is not None: 

581 self._neighbour_buildings = value 

582 else: 

583 self._neighbour_buildings = 0 

584 

585 @property 

586 def attic(self): 

587 return self._attic 

588 

589 @attic.setter 

590 def attic(self, value): 

591 if value is not None: 

592 self._attic = value 

593 else: 

594 self._attic = 0 

595 

596 @property 

597 def cellar(self): 

598 return self._cellar 

599 

600 @cellar.setter 

601 def cellar(self, value): 

602 if value is not None: 

603 self._cellar = value 

604 else: 

605 self._cellar = 0 

606 

607 @property 

608 def dormer(self): 

609 return self._dormer 

610 

611 @dormer.setter 

612 def dormer(self, value): 

613 if value is not None: 

614 self._dormer = value 

615 else: 

616 self._dormer = 0 

617 

618 @property 

619 def construction_data(self): 

620 return self._construction_data 

621 @construction_data.setter 

622 def construction_data(self, value): 

623 self._construction_data = datahandling.check_construction_data_setter_iwu(value)