Source code for honeybee_radiance_postprocess.breeam.breeam

"""Functions for BREEAM post-processing."""
from typing import Union
from pathlib import Path
import json
import numpy as np

from honeybee.model import Model
from honeybee_radiance.writer import _filter_by_pattern

from ..results.annual_daylight import AnnualDaylight


program_type_metrics = {
    'BREEAM::Education_buildings::Preschools': [
        {
            'type': 'Education buildings',
            'credits': 2,
            'area': 80,
            'average_daylight_illuminance': {
                'illuminance': 300,
                'hours': 2000
            },
            'minimum_daylight_illuminance': {
                'illuminance': 90,
                'hours': 2000
            }
        }
    ],
    'BREEAM::Education_buildings::Higher_education': [
        {
            'type': 'Education buildings',
            'credits': 2,
            'area': 80,
            'average_daylight_illuminance': {
                'illuminance': 300,
                'hours': 2000
            },
            'minimum_daylight_illuminance': {
                'illuminance': 90,
                'hours': 2000
            }
        },
        {
            'type': 'Education buildings',
            'credits': 1,
            'area': 60,
            'average_daylight_illuminance': {
                'illuminance': 300,
                'hours': 2000
            },
            'minimum_daylight_illuminance': {
                'illuminance': 90,
                'hours': 2000
            }
        }
    ],
    'BREEAM::Healthcare_buildings::Staff_and_public_areas': [
        {
            'type': 'Healthcare buildings',
            'credits': 2,
            'area': 80,
            'average_daylight_illuminance': {
                'illuminance': 300,
                'hours': 2650
            },
            'minimum_daylight_illuminance': {
                'illuminance': 90,
                'hours': 2650
            }
        },
        {
            'type': 'Healthcare buildings',
            'credits': 1,
            'area': 80,
            'average_daylight_illuminance': {
                'illuminance': 300,
                'hours': 2000
            },
            'minimum_daylight_illuminance': {
                'illuminance': 90,
                'hours': 2000
            }
        }
    ],
    'BREEAM::Healthcare_buildings::Patients_areas_and_consulting_rooms': [
        {
            'type': 'Healthcare buildings',
            'credits': 2,
            'area': 80,
            'average_daylight_illuminance': {
                'illuminance': 300,
                'hours': 2650
            },
            'minimum_daylight_illuminance': {
                'illuminance': 90,
                'hours': 2650
            }
        },
        {
            'type': 'Healthcare buildings',
            'credits': 1,
            'area': 80,
            'average_daylight_illuminance': {
                'illuminance': 300,
                'hours': 2000
            },
            'minimum_daylight_illuminance': {
                'illuminance': 90,
                'hours': 2000
            }
        }
    ],
    'BREEAM::Multi_residential_buildings::Kitchen': [
        {
            'type': 'Multi-residential buildings',
            'credits': 2,
            'area': 100,
            'average_daylight_illuminance': {
                'illuminance': 100,
                'hours': 3450
            },
            'minimum_daylight_illuminance': {
                'illuminance': 30,
                'hours': 3450
            }
        }
    ],
    'BREEAM::Multi_residential_buildings::Living_rooms_dining_rooms_studies': [
        {
            'type': 'Multi-residential buildings',
            'credits': 2,
            'area': 100,
            'average_daylight_illuminance': {
                'illuminance': 100,
                'hours': 3450
            },
            'minimum_daylight_illuminance': {
                'illuminance': 30,
                'hours': 3450
            }
        }
    ],
    'BREEAM::Multi_residential_buildings::Non_residential_or_communal_spaces': [
        {
            'type': 'Multi-residential buildings',
            'credits': 2,
            'area': 80,
            'average_daylight_illuminance': {
                'illuminance': 200,
                'hours': 2650
            },
            'minimum_daylight_illuminance': {
                'illuminance': 60,
                'hours': 2650
            }
        }
    ],
    'BREEAM::Retail_buildings::Sales_areas': [
        {
            'type': 'Retail buildings',
            'credits': 1,
            'area': 35,
            'average_daylight_illuminance': {
                'illuminance': 200,
                'hours': 2650
            },
            'minimum_daylight_illuminance': {
                'illuminance': 200,
                'hours': 2650
            }
        }
    ],
    'BREEAM::Retail_buildings::Other_occupied_areas': [
        {
            'type': 'Retail buildings',
            'credits': 1,
            'area': 80,
            'average_daylight_illuminance': {
                'illuminance': 200,
                'hours': 2650
            },
            'minimum_daylight_illuminance': {
                'illuminance': 60,
                'hours': 2650
            }
        }
    ],
    'BREEAM::Prison_buildings::Cells_and_custody_cells': [
        {
            'type': 'Prison buildings',
            'credits': 2,
            'area': 80,
            'average_daylight_illuminance': {
                'illuminance': 100,
                'hours': 3150
            },
            'minimum_daylight_illuminance': None
        }
    ],
    'BREEAM::Prison_buildings::Internal_association_or_atrium': [
        {
            'type': 'Prison buildings',
            'credits': 2,
            'area': 80,
            'average_daylight_illuminance': {
                'illuminance': 300,
                'hours': 2650
            },
            'minimum_daylight_illuminance': {
                'illuminance': 210,
                'hours': 2650
            }
        }
    ],
    'BREEAM::Prison_buildings::Patient_care_spaces': [
        {
            'type': 'Prison buildings',
            'credits': 2,
            'area': 80,
            'average_daylight_illuminance': {
                'illuminance': 300,
                'hours': 2650
            },
            'minimum_daylight_illuminance': {
                'illuminance': 210,
                'hours': 2650
            }
        }
    ],
    'BREEAM::Prison_buildings::Teaching_lecture_and_seminar_spaces': [
        {
            'type': 'Prison buildings',
            'credits': 2,
            'area': 80,
            'average_daylight_illuminance': {
                'illuminance': 300,
                'hours': 2000
            },
            'minimum_daylight_illuminance': {
                'illuminance': 90,
                'hours': 2000
            }
        }
    ],
    'BREEAM::Office_buildings::Occupied_spaces': [
        {
            'type': 'Office buildings',
            'credits': 2,
            'area': 80,
            'average_daylight_illuminance': {
                'illuminance': 300,
                'hours': 2000
            },
            'minimum_daylight_illuminance': {
                'illuminance': 90,
                'hours': 2000
            }
        }
    ],
    'BREEAM::Crèche_buildings::Occupied_spaces': [
        {
            'type': 'Crèche buildings',
            'credits': 2,
            'area': 80,
            'average_daylight_illuminance': {
                'illuminance': 300,
                'hours': 2000
            },
            'minimum_daylight_illuminance': {
                'illuminance': 90,
                'hours': 2000
            }
        }
    ],
    'BREEAM::Other_buildings::Occupied_spaces': [
        {
            'type': 'Other buildings',
            'credits': 1,
            'area': 80,
            'average_daylight_illuminance': {
                'illuminance': 300,
                'hours': 2000
            },
            'minimum_daylight_illuminance': {
                'illuminance': 90,
                'hours': 2000
            }
        }
    ]
}


[docs] def breeam_daylight_assessment_4b( results: Union[str, AnnualDaylight], model: Union[str, Path, Model] = None, grids_filter: str = '*', sub_folder: str = None): """Calculate credits for BREEAM 4b. Args: results: Path to results folder or a Results class object. model: A model as a path or a HB Model object. If None, the function will look for a model in the parent of the results folder. If a model does not exist in this directory the function will raise an error. Defaults to None. grids_filter: The name of a grid or a pattern to filter the grids. Defaults to '*'. sub_folder: Relative path for a subfolder to write the output. If None, the files will not be written. Defaults to None. Returns: Tuple: - credit_summary: Summary of each building type. - program_summary: Summary of program type / space type. """ if not isinstance(results, AnnualDaylight): results = AnnualDaylight(results) grids_info = results._filter_grids(grids_filter=grids_filter) # check to see if there is a HBJSON with sensor grid meshes for areas grid_areas = {} grid_program_types = {} if model is None: found_file = False for base_file in Path(results.folder).parent.iterdir(): if base_file.suffix in ('.hbjson', '.hbpkl'): hb_model: Model = Model.from_file(base_file) found_file = True break if not found_file: raise FileNotFoundError( 'Found no hbjson or hbpkl file in parent of results folder.') else: if isinstance(model, Model): hb_model = model else: hb_model = Model.from_file(model) filt_grids = _filter_by_pattern( hb_model.properties.radiance.sensor_grids, filter=grids_filter) for s_grid in filt_grids: if s_grid.mesh is not None: grid_areas[s_grid.identifier] = np.array(s_grid.mesh.face_areas).sum() else: grid_areas[s_grid.identifier] = None hb_room = hb_model.rooms_by_identifier([s_grid.room_identifier])[0] try: program_type_id = hb_room.properties.energy.program_type.identifier except AttributeError as e: raise ImportError('honeybee_energy library must be installed to use ' 'breeam_daylight_assessment method. {}'.format(e)) if program_type_id in program_type_metrics: grid_program_types[s_grid.identifier] = program_type_id if not grid_areas: grid_areas = {grid_info['full_id']: None for grid_info in grids_info} type_summary = {} for grid_info in grids_info: program_type = grid_program_types.get(grid_info['full_id'], None) if program_type is None: continue if program_type not in type_summary: type_summary[program_type] = {} type_summary[program_type][grid_info['full_id']] = [] array = results._array_from_states(grid_info, zero_array=True) # calculate average along axis 0 (average for each hour) avg_ill = array.mean(axis=0) metrics_list = program_type_metrics[program_type] for metrics in metrics_list: metrics_summary = {} metrics_summary['type'] = metrics['type'] metrics_summary['area'] = grid_areas[grid_info['full_id']] # calculate number of hours where avg. illuminance > target illuminance target_ill = metrics['average_daylight_illuminance']['illuminance'] hrs_abv = (avg_ill >= target_ill).sum() # check if value is >= target hours target_hrs = metrics['average_daylight_illuminance']['hours'] avg_comply = hrs_abv >= target_hrs # calculate number of hours where illuminance > target illuminance if program_type == 'BREEAM::Prison_buildings::Cells_and_custody_cells': minimum_comply = True else: target_ill = metrics['minimum_daylight_illuminance']['illuminance'] hrs_abv_target = (array >= target_ill).sum(axis=1) # get the minimum, i.e., worst lit point worst_lit_point = np.min(hrs_abv_target) # check if values is >= target hours target_hrs = metrics['minimum_daylight_illuminance']['hours'] minimum_comply = worst_lit_point >= target_hrs metrics_summary['credits'] = metrics['credits'] if avg_comply and minimum_comply: metrics_summary['comply'] = True else: metrics_summary['comply'] = False type_summary[program_type][grid_info['full_id']].append(metrics_summary) program_summary = [] for program_type, grid_summary in type_summary.items(): program_type_summary = {} program_type_summary['program_type'] = program_type program_type_summary['credits'] = 0 # set 0 by default program_type_summary['comply'] = False # set False by default metrics_summary = {} for grid_id, metrics_list in grid_summary.items(): for metric in metrics_list: if metric['credits'] not in metrics_summary: metrics_summary[metric['credits']] = {} metrics_summary[metric['credits']]['type'] = metric['type'] if 'total_area' not in metrics_summary[metric['credits']]: metrics_summary[metric['credits']]['total_area'] = 0 metrics_summary[metric['credits']]['total_area'] += metric['area'] if 'area_comply' not in metrics_summary[metric['credits']]: metrics_summary[metric['credits']]['area_comply'] = 0 if metric['comply']: metrics_summary[metric['credits']]['area_comply'] += metric['area'] for credit, metric_summary in metrics_summary.items(): area_comply_pct = metric_summary['area_comply'] / metric_summary['total_area'] * 100 metric_summary['area_comply_%'] = area_comply_pct for metric in program_type_metrics[program_type]: if credit == metric['credits']: if area_comply_pct >= metric['area']: metric_summary['comply'] = True else: metric_summary['comply'] = False for credit, metric_summary in metrics_summary.items(): if metric_summary['comply'] and credit > program_type_summary['credits']: program_type_summary['comply'] = True program_type_summary['credits'] = credit program_type_summary['total_area'] = metric_summary['total_area'] program_type_summary['area_comply'] = metric_summary['area_comply'] program_type_summary['area_comply_%'] = metric_summary['area_comply_%'] program_type_summary['type'] = metric_summary['type'] else: program_type_summary['total_area'] = metric_summary['total_area'] program_type_summary['area_comply'] = metric_summary['area_comply'] program_type_summary['area_comply_%'] = metric_summary['area_comply_%'] program_type_summary['type'] = metric_summary['type'] program_summary.append(program_type_summary) building_type_summary = {} for _program_summary in program_summary: if _program_summary['type'] not in building_type_summary: building_type_summary[_program_summary['type']] = [] building_type_summary[_program_summary['type']].append(_program_summary) credit_summary = [] for building_type, summary in building_type_summary.items(): _building_type_summary = {} _building_type_summary['type'] = building_type if all([v['comply'] for v in summary]): _building_type_summary['comply'] = True _building_type_summary['credits'] = min([v['credits'] for v in summary]) else: _building_type_summary['comply'] = False _building_type_summary['credits'] = 0 _building_type_summary['total_area'] = sum([v['total_area'] for v in summary]) credit_summary.append(_building_type_summary) if sub_folder: folder = Path(sub_folder) folder.mkdir(parents=True, exist_ok=True) credit_summary_file = folder.joinpath('summary.json') credit_summary_file.write_text(json.dumps(credit_summary, indent=2)) program_summary_file = folder.joinpath('program_summary.json') program_summary_file.write_text(json.dumps(program_summary, indent=2)) return credit_summary, program_summary