Example #1
0
def test_writer():
    """Test creating a new folder."""
    folder_path = r'./tests/assets/temp'
    shutil.rmtree(folder_path, ignore_errors=True)
    rad_folder = Folder(folder_path)
    rad_folder.write(folder_type=2, overwrite=True)

    assert os.path.isdir(rad_folder.folder)
    root_folder = rad_folder.model_folder(full=True)
    assert os.path.isdir(root_folder)
    subfolders = [
        f for f in os.listdir(root_folder)
        if os.path.isdir(_as_posix(os.path.join(root_folder, f)))
    ]

    cfg_names = ['GRID', 'VIEW'
                 ] + [k for k, v in config.minimal.items() if v is True]
    expected_subfolders = [rad_folder._get_folder_name(f) for f in cfg_names]

    assert len(subfolders) == len(expected_subfolders)
    for f in expected_subfolders:
        assert f in subfolders

    # try to remove the folder
    shutil.rmtree(folder_path, ignore_errors=True)
Example #2
0
def test_reader_files():
    radiance_folder = r'./tests/assets/project_folder'
    rad_folder = Folder(radiance_folder)
    assert rad_folder.has_aperture_group
    assert not rad_folder.has_dynamic_scene
    assert rad_folder.aperture_files() == [
        'model/aperture/aperture.mat', 'model/aperture/aperture.rad'
    ]
    assert rad_folder.aperture_files(black_out=True) == [
        'model/aperture/aperture.blk', 'model/aperture/aperture.rad'
    ]

    s_files = rad_folder.scene_files()
    e_files = [
        'model/scene/context.mat', 'model/scene/context.rad',
        'model/scene/partition.mat', 'model/scene/partition.rad',
        'model/scene/partition_glass.mat', 'model/scene/partition_glass.rad',
        'model/scene/room_envelope.mat', 'model/scene/room_envelope.rad'
    ]
    assert s_files.index(e_files[1]) - s_files.index(e_files[0]) == 1
    assert s_files.index(e_files[3]) - s_files.index(e_files[2]) == 1
    assert s_files.index(e_files[5]) - s_files.index(e_files[4]) == 1
    assert s_files.index(e_files[7]) - s_files.index(e_files[6]) == 1

    s_files = rad_folder.scene_files(black_out=True)
    e_files = [
        'model/scene/context.blk', 'model/scene/context.rad',
        'model/scene/partition.blk', 'model/scene/partition.rad',
        'model/scene/partition_glass.blk', 'model/scene/partition_glass.rad',
        'model/scene/room_envelope.blk', 'model/scene/room_envelope.rad'
    ]
    assert s_files.index(e_files[1]) - s_files.index(e_files[0]) == 1
    assert s_files.index(e_files[3]) - s_files.index(e_files[2]) == 1
    assert s_files.index(e_files[5]) - s_files.index(e_files[4]) == 1
    assert s_files.index(e_files[7]) - s_files.index(e_files[6]) == 1
Example #3
0
def test_aperture_group():
    radiance_folder = r'./tests/assets/project_folder'
    folder = Folder(radiance_folder)
    apertures = folder.aperture_groups(interior=False)
    assert len(apertures) == 1
    ap = apertures[0]
    assert ap.states[0].identifier == '0_clear'
    assert ap.states[0].default == 'south_window..default..000.rad'
    assert ap.states[1].identifier == '1_diffuse'
    assert ap.states[1].default == 'south_window..default..001.rad'
Example #4
0
def create_octree_from_folder(
        folder, output, include_aperture, default, add_before, add_after, dry_run):
    """Generate a static octree from a folder.

    folder: Path to a Radiance model folder.
    """
    model_folder = ModelFolder.from_model_folder(folder)
    try:
        black_out = False if default else True
        scene_files = model_folder.scene_files(black_out=black_out)
        if include_aperture:
            # no black out here
            aperture_files = model_folder.aperture_files()
            scene_files += aperture_files
        if add_after:
            scene_files += list(add_after)
        if add_before:
            scene_files = list(add_before) + scene_files
        cmd = Oconv(output=output, inputs=scene_files)
        cmd.options.f = True
        if dry_run:
            click.echo(cmd)
        else:
            env = None
            if folders.env != {}:
                env = folders.env
            env = dict(os.environ, **env) if env else None
            cmd.run(env=env, cwd=model_folder.folder)
    except Exception:
        _logger.exception('Failed to generate octree.')
        sys.exit(1)
    else:
        sys.exit(0)
def test_scene_mapping():
    folder_path = r'./tests/assets/model_folders/simple/model'
    model_folder = Folder.from_model_folder(folder_path)

    # two phase
    scene_mapping = model_folder.octree_scene_mapping(exclude_static=False,
                                                      phase=2)
    os.remove(r'./tests/assets/model_folders/simple/scene_mapping.json')
    assert 'two_phase' in scene_mapping
    assert 'three_phase' not in scene_mapping
    assert 'five_phase' not in scene_mapping
    assert len(scene_mapping['two_phase']) == 11

    # three phase
    scene_mapping = model_folder.octree_scene_mapping(exclude_static=False,
                                                      phase=3)
    os.remove(r'./tests/assets/model_folders/simple/scene_mapping.json')
    assert 'two_phase' in scene_mapping
    assert 'three_phase' in scene_mapping
    assert 'five_phase' not in scene_mapping
    assert len(scene_mapping['two_phase']) == 3

    # five phase
    scene_mapping = model_folder.octree_scene_mapping(exclude_static=False,
                                                      phase=5)
    os.remove(r'./tests/assets/model_folders/simple/scene_mapping.json')
    assert 'two_phase' in scene_mapping
    assert 'three_phase' in scene_mapping
    assert 'five_phase' in scene_mapping
    assert len(scene_mapping['two_phase']) == 3
    assert len(scene_mapping['five_phase']) == 8
def test_grid_mapping():
    folder_path = r'./tests/assets/model_folders/simple/model'
    model_folder = Folder.from_model_folder(folder_path)

    # two phase
    grid_mapping = model_folder.grid_mapping(exclude_static=False, phase=2)
    os.remove(r'./tests/assets/model_folders/simple/grid_mapping.json')
    assert 'two_phase' in grid_mapping
    assert 'three_phase' not in grid_mapping
    assert 'five_phase' not in grid_mapping
    assert len(grid_mapping['two_phase']) == 6

    # three phase
    grid_mapping = model_folder.grid_mapping(exclude_static=False, phase=3)
    os.remove(r'./tests/assets/model_folders/simple/grid_mapping.json')
    assert 'two_phase' in grid_mapping
    assert 'three_phase' in grid_mapping
    assert 'five_phase' not in grid_mapping
    assert len(grid_mapping['two_phase']) == 2
    assert len(grid_mapping['three_phase']) == 4

    # five phase
    grid_mapping = model_folder.grid_mapping(exclude_static=False, phase=5)
    os.remove(r'./tests/assets/model_folders/simple/grid_mapping.json')
    assert 'two_phase' in grid_mapping
    assert 'three_phase' in grid_mapping
    assert 'five_phase' in grid_mapping
    assert len(grid_mapping['two_phase']) == 2
    assert len(grid_mapping['three_phase']) == 4
    assert len(grid_mapping['five_phase']) == 4
def test_scene_mapping_static_model():
    folder_path = r'./tests/assets/model_folders/static/model'
    model_folder = Folder.from_model_folder(folder_path)

    # exclude static apertures
    scene_mapping = model_folder.grid_mapping(exclude_static=False, phase=5)
    os.remove(r'./tests/assets/model_folders/static/grid_mapping.json')
    assert len(scene_mapping['two_phase']) == 1
    assert len(scene_mapping['three_phase']) == 0
    assert len(scene_mapping['five_phase']) == 0

    # do not exclude static apertures
    scene_mapping = model_folder.grid_mapping(exclude_static=True, phase=5)
    os.remove(r'./tests/assets/model_folders/static/grid_mapping.json')
    assert len(scene_mapping['two_phase']) == 0
    assert len(scene_mapping['three_phase']) == 0
    assert len(scene_mapping['five_phase']) == 0
Example #8
0
def create_octree_from_folder_multiphase(folder, sun_path, phase, output_folder):
    """Generate a set of octrees from a folder.

    This command will generate octrees for both default and direct studies. It will do so
    for static apertures and aperture groups, creating one octree for each light path,
    i.e., all other light paths are blacked.

    \b
    Args:
        folder: Path to a Radiance model folder.
    """
    model_folder = ModelFolder.from_model_folder(folder)

    # check if sunpath file exist - otherwise continue without it
    if sun_path and not os.path.isfile(sun_path):
        sun_path = None

    if phase == '5' and not sun_path:
        raise RuntimeError(
            'To generate octrees for a 5 Phase study you must provide a sunpath.'
        )

    phases = {
        '2': ['two_phase'],
        '3': ['two_phase', 'three_phase'],
        '5': ['two_phase', 'three_phase', 'five_phase']
    }

    try:
        scene_mapping = model_folder.octree_scene_mapping()
        if not os.path.isdir(output_folder):
            os.mkdir(output_folder)
        octree_mapping = []
        for study, states in scene_mapping.items():
            if study not in phases[phase]:
                continue
            study_type = []
            for state in states:
                info, commands = _generate_octrees_info(
                    state, output_folder, study, sun_path)
                study_type.append(info)

                for cmd in commands:
                    env = None
                    if folders.env != {}:
                        env = folders.env
                    env = dict(os.environ, **env) if env else None
                    cmd.run(env=env, cwd=model_folder.folder)

            octree_mapping.append({study: study_type})
            octree_output = os.path.join(
                model_folder.folder, output_folder, '%s.json' % study
            )
            with open(octree_output, 'w') as fp:
                json.dump(study_type, fp, indent=2)

        octree_output = os.path.join(
            model_folder.folder, output_folder, 'multi_phase.json'
        )
        with open(octree_output, 'w') as fp:
            json.dump(octree_mapping, fp, indent=2)

    except Exception:
        _logger.exception('Failed to generate octrees.')
        sys.exit(1)
    else:
        sys.exit(0)
Example #9
0
def create_octree_from_shade_trans_groups(folder, sun_path, output_folder):
    """Generate a set of octrees from a folder containing shade transmittance groups.

    This command assumes that each shade group in the radiance folder contains
    only two states. The first is a completely opaque representation of the shade
    group and the second is a completely transparent representation of the shade
    group. This abstracted representation is intended to simulate dynamic shade
    transmittance that changes at each timestep.

    Each shade group will get an octree. If a sun-path is provided, an additional
    octree will be added for each group.

    \b
    Args:
        folder: Path to a Radiance model folder.
    """
    model_folder = ModelFolder.from_model_folder(folder)
    try:
        # first, check to see if there are any shade groups in the model
        output_folder = os.path.join(model_folder.folder, output_folder)
        if not os.path.isdir(output_folder):
            os.mkdir(output_folder)
        group_info_file = os.path.join(output_folder, 'trans_info.json')
        group_info, groups_exist = [], True
        try:
            grp_folder = model_folder.dynamic_scene_folder()
            shd_groups = model_folder.dynamic_scene()
            if len(shd_groups) == 0:
                groups_exist = False
        except Exception:
            groups_exist = False

        if groups_exist:
            # get the static scene files
            scene_files = model_folder.scene_files(black_out=False)
            try:
                aperture_files = model_folder.aperture_files(black_out=False)
                scene_files += aperture_files
            except Exception:
                pass  # no apertures available in the model

            # get the environment variables
            env = None
            if folders.env != {}:
                env = folders.env
            env = dict(os.environ, **env) if env else None

            # loop through the shade groups and create the octrees
            for i, s_grp in enumerate(shd_groups):
                # gather files to represent the transparent shade group
                dyn_grp = [_model_rel(grp_folder, sg.states[0].default)
                           for j, sg in enumerate(shd_groups) if j != i]
                dyn_grp = [sg.replace('\\', '/') for sg in dyn_grp]
                grp_scene_files = scene_files + dyn_grp
                oct_file = os.path.join(output_folder, '{}.oct'.format(s_grp.identifier))
                # command for the octree
                cmds = [Oconv(output=oct_file, inputs=grp_scene_files)]
                # add info about the generated files
                grp_info_dict = {
                    'identifier': s_grp.identifier,
                    'default': os.path.basename(oct_file)
                }
                # command for the octree with suns
                if sun_path and os.path.isfile(sun_path):
                    sun_file = os.path.join(
                        output_folder, '{}_sun.oct'.format(s_grp.identifier))
                    sun_scene_files = [sun_path] + grp_scene_files
                    cmd_ss = Oconv(output=sun_file, inputs=sun_scene_files)
                    cmds.append(cmd_ss)
                    grp_info_dict['sun'] = os.path.basename(sun_file)
                # run all of the commands to create the octrees
                for cmd in cmds:
                    cmd.options.f = True
                    cmd.run(env=env, cwd=model_folder.folder)
                group_info.append(grp_info_dict)

        # write out a JSON with information about the octrees and groups
        with open(group_info_file, 'w') as fp:
            json.dump(group_info, fp, indent=2)
    except Exception:
        _logger.exception('Failed to generate shade trans group octrees.')
        sys.exit(1)
    else:
        sys.exit(0)
Example #10
0
def test_reader():
    radiance_folder = r'./tests/assets/project_folder'
    rad_folder = Folder(radiance_folder)
    assert rad_folder.model_folder() == 'model'
    assert rad_folder.aperture_folder() == _as_posix(
        os.path.join('model', 'aperture'))
    assert rad_folder.aperture_group_folder() == \
        _as_posix(os.path.join('model', 'aperture_group'))
    assert rad_folder.aperture_group_folder(interior=True) == \
        _as_posix(os.path.join('model', 'aperture_group', 'interior'))
    assert rad_folder.bsdf_folder() == _as_posix(os.path.join('model', 'bsdf'))
    assert rad_folder.grid_folder() == _as_posix(os.path.join('model', 'grid'))
    assert rad_folder.ies_folder() == _as_posix(os.path.join('model', 'ies'))
    assert rad_folder.scene_folder() == _as_posix(
        os.path.join('model', 'scene'))
    assert rad_folder.dynamic_scene_folder() == \
        _as_posix(os.path.join('model', 'scene_dynamic'))
    assert rad_folder.dynamic_scene_folder(indoor=True) == \
        _as_posix(os.path.join('model', 'scene_dynamic', 'indoor'))
    assert rad_folder.view_folder() == _as_posix(os.path.join('model', 'view'))
Example #11
0
import ifcopenshell
from honeybee_plus.room import Room
from honeybee_plus.radiance.material.glass import Glass
from honeybee_plus.radiance.properties import RadianceProperties
from honeybee_plus.radiance.sky.certainIlluminance import CertainIlluminanceLevel
from honeybee_plus.radiance.recipe.pointintime.gridbased import GridBased
from honeybee_radiance_folder import ModelFolder
from honeybee_plus.hbsurface import HBSurface
from honeybee_plus.hbfensurface import HBFenSurface
from daylight_analysis_load_IFC_data import *
import os
from dataclasses import dataclass, InitVar

# Set radiance result folder to "room"
rf = "./room"
folder = ModelFolder(rf)
folder.write(overwrite=True)

#########################################
###CREATE WINDOWOUT AND SPACEOUT LISTS###
#########################################

# Temporary variable for storing spaces
out = []

# remove excel formatting for each space.
for i in spaces:
    out.append(SpaceParams((spaceDims(i)), excelFormat=False).out)

# remove empty space entries
spaceOut = [x for x in out if x != []]
Example #12
0
def test_grids():
    project_folder = r'./tests/assets/project_folder'
    folder = Folder(project_folder)
    files = folder.grid_files(rel_path=True)
    assert 'model/grid/cubical.pts' in files
    assert 'model/grid/hallway.pts' in files
def prepare_multiphase_command(folder, grid_count, grid_divisor,
                               min_sensor_count, sun_path, phase,
                               octree_folder, grid_folder, exclude_static):
    """This command prepares the model folder for simulations with aperture groups. It
    will generate a set of octrees and sensor grids that are unique to each state of each
    aperture group.

    This command will generate octrees for both default and direct studies for aperture
    groups, creating one octree for each light path, i.e., all other light paths are
    blacked.

    Sensor grids will be redistributed if they are to be used in a two phase simulation.
    A subfolder for each light path will be created. In this folder the redistributed
    grids are found.

    If the model folder have aperture groups, a file with states information for each
    grid will be written.

    \b
    Args:
        folder: Path to a Radiance model folder.
        grid_count: Number of output sensor grids to be created. This number
            is usually equivalent to the number of processes that will be used to run
            the simulations in parallel.
    """
    model_folder = ModelFolder.from_model_folder(folder)

    # check if sunpath file exist - otherwise continue without it
    if sun_path and not os.path.isfile(sun_path):
        sun_path = None

    phase = int(phase)
    if phase == 5 and not sun_path:
        raise RuntimeError(
            'To generate octrees for a 5 Phase study you must provide a sunpath.'
        )

    phases = {
        2: ['two_phase'],
        3: ['two_phase', 'three_phase'],
        5: ['two_phase', 'three_phase', 'five_phase']
    }

    def _get_grid_states(model_folder=model_folder):
        states_info = model_folder.aperture_groups_states()
        grid_info = model_folder.grid_info()
        grid_states = {}

        for grid in grid_info:
            grid_states[grid['identifier']] = {}
            light_paths = [lp[0] for lp in grid['light_path']]
            for light_path in light_paths:
                if light_path != 'static_apertures':
                    grid_states[grid['identifier']][light_path] = \
                        [s['identifier'] for s in states_info[light_path]]

        grid_states_output = os.path.join(model_folder.folder,
                                          'grid_states.json')
        with open(grid_states_output, 'w') as fp:
            json.dump(grid_states, fp, indent=2)

    def _get_octrees_and_grids(model_folder=model_folder,
                               grid_count=grid_count,
                               phase=phase,
                               octree_folder=octree_folder,
                               grid_folder=grid_folder,
                               exclude_static=exclude_static):
        scene_mapping = model_folder.octree_scene_mapping(
            exclude_static=exclude_static, phase=phase)
        if not os.path.isdir(octree_folder):
            os.mkdir(octree_folder)
        dynamic_mapping = []
        for study, states in scene_mapping.items():
            if study not in phases[phase]:
                continue

            if study == 'two_phase':
                grid_info_dict = {}
                grid_mapping = model_folder.grid_mapping(
                    exclude_static=exclude_static, phase=phase)
                if not os.path.isdir(grid_folder):
                    os.mkdir(grid_folder)

                grid_count = int(grid_count / grid_divisor)
                grid_count = 1 if grid_count < 1 else grid_count

                for light_path in grid_mapping['two_phase']:
                    grid_info = light_path['grid']
                    output_folder = os.path.join(grid_folder,
                                                 light_path['identifier'])
                    _grid_count, _sensor_per_grid, out_grid_info = redistribute_sensors(
                        model_folder.grid_folder(),
                        output_folder,
                        grid_count,
                        min_sensor_count,
                        grid_info=grid_info)
                    grid_info_dict[light_path['identifier']] = out_grid_info

            study_type = []
            for state in states:
                info, commands = _generate_octrees_info(
                    state, octree_folder, study, sun_path)
                study_type.append(info)

                for cmd in commands:
                    env = None
                    if folders.env != {}:
                        env = folders.env
                    env = dict(os.environ, **env) if env else None
                    cmd.run(env=env, cwd=model_folder.folder)

                # add grid information and folder if two_phase
                if study == 'two_phase':
                    info['sensor_grids_folder'] = state['light_path']
                    info['sensor_grids_info'] = grid_info_dict[
                        state['light_path']]

            dynamic_mapping.append({study: study_type})
            dynamic_output = os.path.join(model_folder.folder,
                                          '%s.json' % study)
            with open(dynamic_output, 'w') as fp:
                json.dump(study_type, fp, indent=2)

        dynamic_output = os.path.join(model_folder.folder, 'multi_phase.json')
        with open(dynamic_output, 'w') as fp:
            json.dump(dynamic_mapping, fp, indent=2)

    try:
        if model_folder.has_aperture_group or not exclude_static:
            _get_octrees_and_grids(model_folder=model_folder,
                                   grid_count=grid_count,
                                   phase=phase,
                                   octree_folder=octree_folder,
                                   grid_folder=grid_folder,
                                   exclude_static=exclude_static)
            if model_folder.has_aperture_group:
                _get_grid_states(model_folder=model_folder)
        else:
            # no aperture groups and static excluded, write empty files
            dynamic_mapping = []
            for study in phases[phase]:
                study_type = []
                dynamic_mapping.append({study: study_type})
                dynamic_output = os.path.join(model_folder.folder,
                                              '%s.json' % study)
                with open(dynamic_output, 'w') as fp:
                    json.dump(study_type, fp, indent=2)

            dynamic_output = os.path.join(model_folder.folder,
                                          'multi_phase.json')
            with open(dynamic_output, 'w') as fp:
                json.dump(dynamic_mapping, fp, indent=2)

    except Exception:
        _logger.exception('Failed to generate octrees and grids.')
        sys.exit(1)
    else:
        sys.exit(0)
def dmtx_group_command(
    folder,
    octree,
    rflux_sky,
    name,
    size,
    threshold,
    ambient_division,
    output_folder,
):
    """Calculate aperture groups for daylight matrix purposes.
    This command calculates view factor from apertures to sky patches (rfluxmtx). Each
    aperture is represented by a sensor grid, and the view factor for the whole aperture
    is the average of the grid. The apertures are grouped based on the threshold.
    \b
    Args:
        folder: Path to a Radiance model folder.
        octree: Path to octree file.
        rflux_sky: Path to rflux sky file.
    """
    def _index_and_min(distance_matrix):
        """Return the minimum value of the distance matrix, as well as the index [j, i] of
        the minimum value of the distance matrix."""
        min_value = min([min(sublist) for sublist in distance_matrix])
        for i, _i in enumerate(distance_matrix):
            for j, _j in enumerate(distance_matrix):
                if distance_matrix[i][j] == min_value:
                    index = [j, i]
                    break
        return min_value, index

    def _pairwise_maximum(array1, array2):
        """Return an array of the pairwise maximum of two arrays."""
        pair_array = [array1, array2]
        max_array = list(map(max, zip(*pair_array)))
        return max_array

    def _tranpose_matrix(matrix):
        """Transposes the distance matrix."""
        matrix = list(map(list, zip(*matrix)))
        return matrix

    def _rmse_from_matrix(input):
        """Calculates RMSE."""
        rmse = []
        for i, predicted in enumerate(input):
            r_list = []
            for j, observed in enumerate(input):
                error = [(p - o) for p, o in zip(predicted, observed)]
                square_error = [e**2 for e in error]
                mean_square_error = sum(square_error) / len(square_error)
                root_mean_square_error = mean_square_error**0.5
                r_list.append(root_mean_square_error)
            rmse.append(r_list)
        return rmse

    def _flatten(container):
        """Flatten an array."""
        if not isinstance(container, list):
            container = [container]
        for i in container:
            if isinstance(i, (list, tuple)):
                for j in _flatten(i):
                    yield j
            else:
                yield i

    def _agglomerative_clustering_complete(distance_matrix,
                                           ap_name,
                                           threshold=0.001):
        """Cluster apertures based on the threshold."""

        # Fill the diagonal with 9999 so a diagonal of zeros will NOT be stored as min_value.
        for i in range(len(distance_matrix)):
            distance_matrix[i][i] = 9999

        # Create starting list of aperture groups. Each aperture starts as its own group.
        ap_groups = ap_name

        # Set the number of samples and the minimum value of the distance matrix.
        n_samples = len(distance_matrix)

        # Set the minimum value of the distance matrix and find the indices of the minimum
        # value in the distance matrix.
        min_value, index = _index_and_min(distance_matrix)

        while n_samples > 1 and min_value < threshold:
            # Combine the two groups and place it at index 0, and remove item at index 1.
            ap_groups[index[0]] = [ap_groups[index[0]], ap_groups[index[1]]]
            ap_groups.pop(index[1])

            # Update the values in the distance matrix. We need the maximum values between
            # the new cluster and all the remaining apertures or clusters still in the
            # distance matrix.
            distance_matrix[index[0]] = \
                _pairwise_maximum(distance_matrix[index[0]], distance_matrix[index[1]])
            distance_matrix = _tranpose_matrix(distance_matrix)
            distance_matrix[index[0]] = \
                _pairwise_maximum(distance_matrix[index[0]], distance_matrix[index[1]])

            # Remove the values at index 1 along both axes.
            distance_matrix.pop(index[1])
            distance_matrix = _tranpose_matrix(distance_matrix)
            distance_matrix.pop(index[1])

            # Update the number of samples that are left in the distance matrix.
            n_samples -= 1
            # Update the minimum value and the indices.
            min_value, index = _index_and_min(distance_matrix)

        return ap_groups

    def _aperture_view_factor(project_folder,
                              apertures,
                              size=0.2,
                              ambient_division=1000,
                              receiver='rflux_sky.sky',
                              octree='scene.oct',
                              calc_folder='dmtx_aperture_grouping'):
        """Calculates the view factor for each aperture by sensor points."""

        # Instantiate dictionary that will store the sensor count for each aperture. We need
        # a OrderedDict so that we can split the rfluxmtx output file by each aperture
        # (sensor count) in the correct order.
        ap_dict = OrderedDict()

        meshes = []
        # Create a mesh for each aperture and add the the sensor count to dict.
        for aperture in apertures:
            ap_mesh = aperture.geometry.mesh_grid(size,
                                                  flip=True,
                                                  generate_centroids=False)
            meshes.append(ap_mesh)
            ap_dict[aperture.display_name] = {
                'sensor_count': len(ap_mesh.faces)
            }

        # Create a sensor grid from joined aperture mesh.
        grid_mesh = SensorGrid.from_mesh3d('aperture_grid',
                                           Mesh3D.join_meshes(meshes))

        # Write sensor grid to pts file.
        sensors = grid_mesh.to_file(os.path.join(project_folder, calc_folder),
                                    file_name='apertures')

        # rfluxmtx options
        rfluxOpt = RfluxmtxOptions()
        rfluxOpt.ad = ambient_division
        rfluxOpt.lw = 1.0 / float(rfluxOpt.ad)
        rfluxOpt.I = True
        rfluxOpt.h = True

        # rfluxmtx command
        rflux = Rfluxmtx()
        rflux.options = rfluxOpt
        rflux.receivers = receiver
        rflux.sensors = sensors
        rflux.octree = octree
        rflux.output = os.path.join(calc_folder, 'apertures_vf.mtx')

        # Run rfluxmtx command
        rflux.run(cwd=project_folder)

        # Get the output file of the rfluxmtx command.
        mtx_file = os.path.join(project_folder, rflux.output)

        return mtx_file, ap_dict

    try:
        model_folder = ModelFolder.from_model_folder(folder)

        apertures = []
        states = model_folder.aperture_groups_states(full=True)
        ap_group_folder = model_folder.aperture_group_folder(full=True)
        for ap_group in states.keys():
            if 'dmtx' in states[ap_group][0]:
                mtx_file = os.path.join(
                    ap_group_folder,
                    os.path.basename(states[ap_group][0]['dmtx']))
                polygon_string = parse_from_file(mtx_file)
                polygon = Polygon.from_string('\n'.join(polygon_string))
                apertures.append(
                    Aperture.from_vertices(ap_group, polygon.vertices))

        assert len(apertures) != 0, \
            'Found no valid dynamic apertures. There should at least be one aperture ' \
            'with transmittance matrix in your model.'

        # Calculate view factor.
        mtx_file, ap_dict = _aperture_view_factor(
            model_folder.folder,
            apertures,
            size=size,
            ambient_division=ambient_division,
            receiver=rflux_sky,
            octree=octree,
            calc_folder=output_folder)

        view_factor = []
        # Read view factor file, convert to one channel output, and divide by Pi.
        with open(mtx_file) as mtx_data:
            for sensor in mtx_data:
                sensor_split = sensor.strip().split()
                if len(sensor_split) % 3 == 0:
                    one_channel = sensor_split[::3]
                    convert_to_vf = lambda x: float(x) / math.pi
                    view_factor.append(list(map(convert_to_vf, one_channel)))

        ap_view_factor = []
        # Split the view factor file by the aperture sensor count.
        for aperture in ap_dict.values():
            sensor_count = aperture['sensor_count']
            ap_vf, view_factor = view_factor[:sensor_count], view_factor[
                sensor_count:]
            ap_view_factor.append(ap_vf)

        ap_view_factor_mean = []
        # Get the mean view factor per sky patch for each aperture.
        for aperture in ap_view_factor:
            ap_t = _tranpose_matrix(aperture)
            ap_view_factor_mean.append(
                [sum(sky_patch) / len(sky_patch) for sky_patch in ap_t])

        # Calculate RMSE between all combinations of averaged aperture view factors.
        rmse = _rmse_from_matrix(ap_view_factor_mean)

        ap_name = list(ap_dict.keys())
        # Cluster the apertures by the 'complete method'.
        ap_groups = _agglomerative_clustering_complete(rmse, ap_name,
                                                       threshold)

        # Flatten the groups. This will break the intercluster structure, but we do not need
        # to know that.
        ap_groups = [list(_flatten(cluster)) for cluster in ap_groups]

        # Add the aperture group to each aperture in the dictionary and write the aperture
        # group rad files.
        group_names = []
        groups_folder = os.path.join(model_folder.folder, output_folder,
                                     'groups')
        if not os.path.isdir(groups_folder):
            os.mkdir(groups_folder)
        for idx, group in enumerate(ap_groups):
            group_name = "group_{}".format(idx)
            group_file = os.path.join(groups_folder, group_name + '.rad')
            xform = []
            group_names.append({
                'identifier': group_name,
                'aperture_groups': group
            })

            for ap in group:
                xform.append(
                    "!xform ./model/aperture_group/{}..mtx.rad".format(ap))

            with open(group_file, "w") as file:
                file.write('\n'.join(xform))

        # Write aperture dictionary to json file.
        output = os.path.join(model_folder.folder, output_folder, 'groups',
                              '%s.json' % name)
        with open(output, 'w') as fp:
            json.dump(group_names, fp, indent=2)

    except Exception:
        _logger.exception("Failed to run dmtx-group command.")
        traceback.print_exc()
        sys.exit(1)
    else:
        sys.exit(0)
Example #15
0
def create_octree_from_abstracted_groups(folder, sun_path, output_folder):
    """Generate a set of octrees from a folder containing abstracted aperture groups.

    This command assumes that each aperture group in the radiance folder contains
    only two states. The first is a 100 percent transmittance specular (or beam)
    representation of the aperture group and the second is a 100 percent transmittance
    diffuse representation of the aperture group. This abstracted representation is
    intended to simulate contributions of dynamic groups when an external source
    is able to provide specular and diffuse transmittances at each timestep.
    For example, EnergyPlus can provide such values, which together can account
    for several types of complex dynamic fenestration types.

    Each aperture group will get at least two octrees (one with specular and one
    with diffuse). If a sun-path is provided, a third octree will be added with
    the suns included.

    \b
    Args:
        folder: Path to a Radiance model folder.
    """
    model_folder = ModelFolder.from_model_folder(folder)
    try:
        # first, check to see if there are any aperture groups in the model
        output_folder = os.path.join(model_folder.folder, output_folder)
        if not os.path.isdir(output_folder):
            os.mkdir(output_folder)
        group_info_file = os.path.join(output_folder, 'group_info.json')
        group_info, groups_exist = [], True
        try:
            grp_folder = model_folder.aperture_group_folder()
            ap_groups = model_folder.aperture_groups()
            if len(ap_groups) == 0:
                groups_exist = False
        except Exception:
            groups_exist = False

        if groups_exist:
            # get the static scene files with blacked-out apertures
            scene_files = model_folder.scene_files(black_out=False)
            try:
                aperture_files = model_folder.aperture_files(black_out=True)
                scene_files += aperture_files
            except Exception:
                pass  # no apertures available in the model

            # get the environment variables
            env = None
            if folders.env != {}:
                env = folders.env
            env = dict(os.environ, **env) if env else None

            # loop through the aperture groups and create the octrees
            for i, a_grp in enumerate(ap_groups):
                # create a sub-folder and get black versions of all other aperture groups
                sub_folder = os.path.join(output_folder, a_grp.identifier)
                if not os.path.isdir(sub_folder):
                    os.mkdir(sub_folder)
                blk_grp = [_model_rel(grp_folder, ag.states[0].black)
                           for j, ag in enumerate(ap_groups) if j != i]
                blk_grp = [bg.replace('\\', '/') for bg in blk_grp]
                grp_scene_files = scene_files + blk_grp
                # command for the octree for specular transmittance
                spec_file = os.path.join(sub_folder, 'spec.oct')
                spec_scene_files = grp_scene_files + \
                    [_model_rel(grp_folder, a_grp.states[0].default)]
                cmd_s = Oconv(output=spec_file, inputs=spec_scene_files)
                # command for the octree for diffuse transmittance
                diff_file = os.path.join(sub_folder, 'diff.oct')
                diff_scene_files = grp_scene_files + \
                    [_model_rel(grp_folder, a_grp.states[1].default)]
                cmd_d = Oconv(output=diff_file, inputs=diff_scene_files)
                cmds = [cmd_s, cmd_d]
                # add info about the generated files
                grp_info_dict = {
                    'identifier': a_grp.identifier,
                    'spec': os.path.basename(spec_file),
                    'diff': os.path.basename(diff_file)
                }
                # command for the octree with suns
                if sun_path and os.path.isfile(sun_path):
                    spec_sun_file = os.path.join(sub_folder, 'spec_sun.oct')
                    spec_sun_scene_files = [sun_path] + spec_scene_files
                    cmd_ss = Oconv(output=spec_sun_file, inputs=spec_sun_scene_files)
                    cmds.append(cmd_ss)
                    grp_info_dict['sun'] = os.path.basename(spec_sun_file)
                # run all of the commands to create the octrees
                for cmd in cmds:
                    cmd.options.f = True
                    cmd.run(env=env, cwd=model_folder.folder)
                group_info.append(grp_info_dict)

        # write out a JSON with information about the octrees and groups
        with open(group_info_file, 'w') as fp:
            json.dump(group_info, fp, indent=2)
    except Exception:
        _logger.exception('Failed to generate abstracted group octrees.')
        sys.exit(1)
    else:
        sys.exit(0)
Example #16
0
def test_static_aperture():
    radiance_folder = r'./tests/assets/project_folder'
    folder = Folder(radiance_folder)
    files = folder.aperture_files(black_out=False, rel_path=True)
    assert 'model/aperture/aperture.mat' in files
    assert 'model/aperture/aperture.rad' in files
Example #17
0
def create_octree_from_folder(
    folder, output, default, include_aperture, black_groups, first_shade_state,
    include_ies, add_before, add_after, dry_run
):
    """Generate a static octree from a folder.

    \b
    Args:
        folder: Path to a Radiance model folder.
    """
    model_folder = ModelFolder.from_model_folder(folder)
    try:
        black_out = False if default else True
        scene_files = model_folder.scene_files(black_out=black_out)
        if include_aperture:  # no black out here
            try:
                aperture_files = model_folder.aperture_files()
                scene_files += aperture_files
            except Exception:
                pass  # no apertures available in the model
        if black_groups:
            try:
                group_files = model_folder.aperture_group_files_black()
                scene_files += group_files
            except Exception:
                pass  # no aperture groups available in the model
        if first_shade_state:
            try:
                dyn_folder = model_folder.dynamic_scene_folder(full=True)
                dyn_shades = model_folder.dynamic_scene()
                shd_g_files = [os.path.join(dyn_folder, grp.states[0].default)
                               for grp in dyn_shades]
                scene_files += shd_g_files
            except Exception:
                pass  # no shade groups available in the model
        if include_ies:
            try:
                ies_folder = model_folder.ies_folder()
                for fp in os.listdir(ies_folder):
                    if fp.endswith('rad'):
                        scene_files += os.path.join(ies_folder, fp)
            except Exception:
                pass  # no aperture groups available in the model
        if add_after:
            scene_files += list(add_after)
        if add_before:
            scene_files = list(add_before) + scene_files
        cmd = Oconv(output=output, inputs=scene_files)
        cmd.options.f = True
        if dry_run:
            click.echo(cmd)
        else:
            env = None
            if folders.env != {}:
                env = folders.env
            env = dict(os.environ, **env) if env else None
            cmd.run(env=env, cwd=model_folder.folder)
    except Exception:
        _logger.exception('Failed to generate octree.')
        sys.exit(1)
    else:
        sys.exit(0)