"""A collection of useful methods for multi-phase recipes."""
from .recipedcutil import window_group_to_receiver, coeff_matrix_commands, sky_receiver
from .recipedcutil import matrix_calculation, rgb_matrix_file_to_ill, \
sun_coeff_matrix_commands
from .recipedcutil import sun_matrix_calculation, final_matrix_addition
from ...futil import preparedir, copy_files_to_folder
import os
from collections import namedtuple
[docs]def write_rad_files_multi_phase(working_dir, project_name, opq, glz, wgs):
"""Write files to a target directory for multi-phase method.
This method should only be used for daylight coefficeint and multi-phase
daylight simulations. The files will be written under
working_dir/opaque
working_dir/glazing
working_dir/wgroup
Args:
working_dir: Path to working directory.
opq: A RadFile for opaque surfaces.
glz: A RadFile for glazing surfaces.
wgs: A collection of RadFiles for window-groups.
Returns:
A named tuple for each RadFile as (fp, fpblk, fpglw)
fp returns the file path to the list of radiance files. It will be glowed
files for window_groups.
fpblk returns the file path to the list of blacked radiance files.
"""
Files = namedtuple('Files', ['fp', 'fpblk', 'fpglw'])
folder = os.path.join(working_dir, 'opaque')
of = opq.write_geometries(folder, '%s..opq.rad' % project_name, 0, mkdir=True)
om = opq.write_materials(folder, '%s..opq.mat' % project_name, 0, blacked=False)
bm = opq.write_materials(folder, '%s..blk.mat' % project_name, 0, blacked=True)
opqf = Files((om, of), (bm, of), ())
folder = os.path.join(working_dir, 'glazing')
ogf = glz.write_geometries(folder, '%s..glz.rad' % project_name, 0, mkdir=True)
ogm = glz.write_materials(folder, '%s..glz.mat' % project_name, 0, blacked=False)
bgm = glz.write_materials(folder, '%s..blk.mat' % project_name, 0, blacked=True)
glzf = Files((ogm, ogf), (bgm, ogf), ())
wgfs = []
folder = os.path.join(working_dir, 'wgroup')
bsdfs = []
bsdffolder = os.path.join(working_dir, 'bsdf')
preparedir(bsdffolder)
# write black material to folder
for count, wgf in enumerate(wgs):
# write it as a black geometry
wg = wgf.hb_surfaces[0]
name = wg.name
if count == 0:
wgbm = wgf.write_black_material(folder, 'black.mat', mkdir=True)
wgbf = wgf.write_geometries_blacked(folder, '%s..blk.rad' % name, 0)
wggf = wgf.write(folder, '%s..glw.rad' % name, 0, flipped=True,
glowed=True, mkdir=True)
recf = window_group_to_receiver(wggf, wg.upnormal, wg.radiance_material.name,
wg.radiance_material.angle_basis)
# remove the original window group and rename the new one to original
os.remove(wggf)
os.rename(recf, wggf)
# copy xml files for each state to bsdf folder
# raise TypeError if material is not BSDF
# write files for each state
wgfstate = []
for scount, state in enumerate(wg.states):
wg.state = scount
assert hasattr(wg.radiance_material, 'xmlfile'), \
ValueError(
'RadianceMaterial for all the states should be BSDF material.'
' Radiance Material for {} state is {}.'.format(
state.name, type(wg.radiance_material)))
bsdfs.append(wg.radiance_material.xmlfile)
# write the file for each state. only useful for 5-phase
wgfst = wgf.write(folder, '%s..%s.rad' % (name, state.name), 0)
wgfstate.append(wgfst)
wg.state = 0 # set the state back to 0
wgfs.append(Files(wgfstate, (wgbm, wgbf), (wggf,)))
copy_files_to_folder(bsdfs, bsdffolder)
return opqf, glzf, wgfs
[docs]def get_commands_view_daylight_matrices(
project_folder, window_group, count, inputfiles, points_file,
number_of_points, sky_density, view_mtx_parameters, daylight_mtx_parameters,
reuse_view_mtx=False, reuse_daylight_mtx=False, phases_count=3):
"""Get commnds, view matrix file and daylight matrix file."""
commands = []
opqfiles, glzfiles, wgsfiles, extrafiles = inputfiles
# add material file
blkmaterial = [wgsfiles[count].fpblk[0]]
# add all the blacked window groups but the one in use
# and finally add non-window group glazing as black
wgsblacked = \
[f.fpblk[1] for c, f in enumerate(wgsfiles) if c != count] + \
list(glzfiles.fpblk)
# for scount, state in enumerate(wg.states):
# 2.3.Generate daylight coefficients using rfluxmtx
# collect list of radiance files in the scene for both total and direct
commands.append(
':: start of the 3-phase calculation for the window group {}'.format(
window_group.name)
)
vreceiver = wgsfiles[count].fpglw[0]
vrflux_scene = (
f for fl in
(opqfiles.fp, blkmaterial, wgsblacked)
for f in fl)
drflux_scene = (
f for fl in
(opqfiles.fp, extrafiles.fp, blkmaterial, wgsblacked)
for f in fl)
# 3.2.Generate view matrix
v_matrix = 'result/matrix/{}.vmx'.format(window_group.name)
if not os.path.isfile(os.path.join(project_folder, v_matrix)) \
or not reuse_view_mtx:
commands.append(':: :: [1/{}] calculating view matrix'.format(phases_count))
commands.append(
':: :: rfluxmtx - [wgroup] [scene] [points] [blacked wgroups]'
' ^> [*.vmx]'
)
commands.append('::')
# prepare input files
rad_files = tuple(os.path.relpath(f, project_folder) for f in vrflux_scene)
vmtx = coeff_matrix_commands(
v_matrix, os.path.relpath(vreceiver, project_folder), rad_files, '-',
os.path.relpath(points_file, project_folder), number_of_points,
view_mtx_parameters)
commands.append(vmtx.to_rad_string())
# 3.3 daylight matrix
d_matrix = 'result/matrix/{}_{}.dmx'.format(window_group.name, sky_density)
if not os.path.isfile(os.path.join(project_folder, d_matrix)) \
or not reuse_daylight_mtx:
sender = os.path.relpath(vreceiver, project_folder)
receiver = sky_receiver(
os.path.join(project_folder, 'sky/rfluxSky.rad'), sky_density
)
rad_files = tuple(os.path.relpath(f, project_folder) for f in drflux_scene)
dmtx = coeff_matrix_commands(
d_matrix, os.path.relpath(receiver, project_folder), rad_files,
sender, None, None, daylight_mtx_parameters)
commands.append(':: :: [2/{}] calculating daylight matrix'.format(phases_count))
commands.append(
':: :: rfluxmtx - [sky] [points] [wgroup] [blacked wgroups] [scene]'
' ^> [*.dmx]'
)
commands.append('::')
commands.append(dmtx.to_rad_string())
return commands, v_matrix, d_matrix
[docs]def get_commands_direct_view_daylight_matrices(
project_folder, window_group, count, inputfiles, points_file,
number_of_points, sky_density, view_mtx_parameters, daylight_mtx_parameters,
reuse_view_mtx=False, reuse_daylight_mtx=False):
"""Get commnds, view matrix file and daylight matrix file for direct calculation."""
commands = []
opqfiles, glzfiles, wgsfiles, extrafiles = inputfiles
# add material file
blkmaterial = [wgsfiles[count].fpblk[0]]
# add all the blacked window groups but the one in use
# and finally add non-window group glazing as black
wgsblacked = \
[f.fpblk[1] for c, f in enumerate(wgsfiles) if c != count] + \
list(glzfiles.fpblk)
# for scount, state in enumerate(wg.states):
# 2.3.Generate daylight coefficients using rfluxmtx
# collect list of radiance files in the scene for both total and direct
commands.append(
':: start of the 3-phase direct calculation for the window group {}'.format(
window_group.name)
)
vreceiver = wgsfiles[count].fpglw[0]
# change here to create a black scene instead
vrflux_scene = (
f for fl in
(opqfiles.fpblk, blkmaterial, wgsblacked)
for f in fl)
drflux_scene = (
f for fl in
(opqfiles.fpblk, extrafiles.fpblk, blkmaterial, wgsblacked)
for f in fl)
# 3.2.Generate view matrix
v_matrix = 'result/matrix/{}_dir.vmx'.format(window_group.name)
if not os.path.isfile(os.path.join(project_folder, v_matrix)) \
or not reuse_view_mtx:
commands.append(':: :: [4-1/5] calculating direct view matrix')
commands.append(
':: :: rfluxmtx - [wgroup] [blacked scene] [points] [blacked wgroups]'
' ^> [*.vmx]'
)
commands.append('::')
# prepare input files
rad_files = tuple(os.path.relpath(f, project_folder) for f in vrflux_scene)
ab = int(view_mtx_parameters.ambient_bounces)
view_mtx_parameters.ambient_bounces = 1
vmtx = coeff_matrix_commands(
v_matrix, os.path.relpath(vreceiver, project_folder), rad_files, '-',
os.path.relpath(points_file, project_folder), number_of_points,
view_mtx_parameters)
view_mtx_parameters.ambient_bounces = ab
commands.append(vmtx.to_rad_string())
# 3.3 daylight matrix
d_matrix = 'result/matrix/{}_{}_dir.dmx'.format(window_group.name, sky_density)
if not os.path.isfile(os.path.join(project_folder, d_matrix)) \
or not reuse_daylight_mtx:
sender = os.path.relpath(vreceiver, project_folder)
receiver = sky_receiver(
os.path.join(project_folder, 'sky/rfluxSky.rad'), sky_density
)
rad_files = tuple(os.path.relpath(f, project_folder) for f in drflux_scene)
ab = int(daylight_mtx_parameters.ambient_bounces)
src = int(daylight_mtx_parameters.sampling_rays_count)
daylight_mtx_parameters.ambient_bounces = 1
daylight_mtx_parameters.sampling_rays_count = 1
dmtx = coeff_matrix_commands(
d_matrix, os.path.relpath(receiver, project_folder), rad_files,
sender, None, None, daylight_mtx_parameters)
daylight_mtx_parameters.ambient_bounces = ab
daylight_mtx_parameters.sampling_rays_count = src
commands.append(':: :: [4-2/5] calculating direct daylight matrix')
commands.append(
':: :: rfluxmtx - [sky] [points] [wgroup] [blacked wgroups] [blacked scene]'
' ^> [*.dmx]'
)
commands.append('::')
commands.append(dmtx.to_rad_string())
return commands, v_matrix, d_matrix
[docs]def matrix_calculation_three_phase(
project_folder, window_group, v_matrix, d_matrix, sky_mtx_total,
transpose=False):
"""Three phase matrix calculation.
Args:
project_folder: Full path to project folder.
window_group: A window_group.
v_matrix: Path to view matrix.
d_matrix: Path to daylight matrix.
sky_mtx_total: Path to sky matrix.
Returns:
commands, result_files
"""
commands = []
results = []
for stcount, state in enumerate(window_group.states):
# 4. matrix calculations
window_group.state = stcount
t_matrix = 'scene/bsdf/{}'.format(
os.path.split(window_group.radiance_material.xmlfile)[-1])
output = r'tmp/{}..{}.tmp'.format(window_group.name, state.name)
dct = matrix_calculation(output, v_matrix, t_matrix, d_matrix, sky_mtx_total)
commands.append(':: :: State {} [{} out of {}]'
.format(state.name, stcount + 1, len(window_group.states)))
commands.append(':: :: [3/3] v_matrix * d_matrix * t_matrix')
commands.append(':: :: dctimestep [vmx] [tmtx] [dmtx] ^ > [results.rgb]')
commands.append(dct.to_rad_string())
# 5. convert r, g ,b values to illuminance
final_output = r'result/{}..{}.ill'.format(window_group.name, state.name)
finalmtx = rgb_matrix_file_to_ill((dct.output_file,), final_output, transpose)
commands.append(
':: :: rmtxop -c 47.4 119.9 11.6 [results.rgb] ^> [results.ill]')
commands.append('::')
commands.append('::')
commands.append(finalmtx.to_rad_string())
results.append(os.path.join(project_folder, final_output))
return commands, results
[docs]def matrix_calculation_five_phase(
project_name, sky_density, project_folder, window_group, skyfiles,
inputfiles, points_file, total_point_count, rfluxmtx_parameters, v_matrix,
d_matrix, dv_matrix, dd_matrix, window_group_count=0, reuse_view_mtx=False,
reuse_daylight_mtx=False, counter=None, transpose=False):
"""Get commands for the five phase recipe.
This function takes the result_files from 3phase calculation and adds direct
calculation phases to it.
"""
commands = []
results = []
# unpack inputs
opqfiles, glzfiles, wgsfiles, extrafiles = inputfiles
sky_mtx_total, sky_mtx_direct, analemma, sunlist, analemmaMtx = skyfiles
# get black material file
blkmaterial = [wgsfiles[window_group_count].fpblk[0]]
# add all the blacked window groups but the one in use
# and finally add non-window group glazing as black
wgsblacked = \
[f.fpblk[1] for c, f in enumerate(wgsfiles) if c != window_group_count] + \
list(glzfiles.fpblk)
for scount, state in enumerate(window_group.states):
# 2.3.Generate daylight coefficients using rfluxmtx
# collect list of radiance files in the scene for both total and direct
if counter:
p = ((counter[0] + scount - 1.0) / counter[1]) * 100
c = int(p / 10)
commands.append(
':: {} of {} ^|{}{}^| ({:.2f}%%)'.format(
counter[0] + scount - 1, counter[1], '#' * c,
'-' * (10 - c), float(p)
)
)
commands.append('::')
# TODO(mostapha): only calculate it if either view materix of daylight matrix
# is recalculated or t-matrix is new.
window_group.state = scount
t_matrix = 'scene/bsdf/{}'.format(
os.path.split(window_group.radiance_material.xmlfile)[-1])
output = r'tmp/3phase..{}..{}.tmp'.format(window_group.name, state.name)
dct = matrix_calculation(output, v_matrix, t_matrix, d_matrix, sky_mtx_total)
commands.append(':: :: [3/5] v_matrix * d_matrix * t_matrix')
commands.append(':: :: dctimestep [vmx] [tmtx] [dmtx] ^ > [results.rgb]')
commands.append(dct.to_rad_string())
# 5. convert r, g ,b values to illuminance
final_output = r'result/3phase..{}..{}.ill'.format(
window_group.name, state.name)
finalmtx = rgb_matrix_file_to_ill((dct.output_file,), final_output, transpose)
commands.append(finalmtx.to_rad_string())
results.append(os.path.join(project_folder, final_output))
commands.append('::')
# calculate direct matrix with black scene
output = r'tmp/direct..{}..{}.tmp'.format(window_group.name, state.name)
dct = matrix_calculation(output, dv_matrix, t_matrix, dd_matrix, sky_mtx_direct)
commands.append(':: :: [4/5] v_matrix * d_matrix * t_matrix')
commands.append(':: :: dctimestep [vmx] [tmtx] [dmtx] ^ > [results.rgb]')
commands.append(dct.to_rad_string())
# 5. convert r, g ,b values to illuminance
final_output = r'result/direct..{}..{}.ill'.format(
window_group.name, state.name)
finalmtx = rgb_matrix_file_to_ill((dct.output_file,), final_output, transpose)
commands.append(finalmtx.to_rad_string())
results.append(os.path.join(project_folder, final_output))
commands.append('::')
# in case window group is not already provided
window_groupfiles = (wgsfiles[window_group_count].fp[scount],)
rflux_scene_blacked = (
f for fl in
(window_groupfiles, opqfiles.fpblk, extrafiles.fpblk,
blkmaterial, wgsblacked)
for f in fl)
sun_matrix = 'result/matrix/sun_{}..{}..{}.dc'.format(
project_name, window_group.name, state.name)
if not os.path.isfile(os.path.join(project_folder, sun_matrix)) \
or not reuse_daylight_mtx:
rad_files_blacked = tuple(os.path.relpath(f, project_folder)
for f in rflux_scene_blacked)
# replace the 4th phase with the new function
commands.append(':: :: [5/5] black scene analemma daylight matrix')
commands.append(
':: :: rcontrib - [sun_matrix] [points] [wgroup] [blacked wgroups] '
'[blacked scene] ^> [analemma dc.mtx]'
)
commands.append('::')
sun_commands = sun_coeff_matrix_commands(
sun_matrix, os.path.relpath(points_file, project_folder),
rad_files_blacked, os.path.relpath(analemma, project_folder),
sunlist, rfluxmtx_parameters.irradiance_calc
)
commands.extend(cmd.to_rad_string() for cmd in sun_commands)
else:
commands.append(':: :: reusing daylight matrices')
commands.append('::')
commands.append(':: :: calculating black daylight mtx * analemma')
commands.append(
':: :: dctimestep [black dc.mtx] [analemma only sky] ^> [sun results.rgb]')
dct_sun = sun_matrix_calculation(
'tmp/sun..{}..{}.rgb'.format(window_group.name, state.name),
dc_matrix=sun_matrix,
sky_matrix=os.path.relpath(analemmaMtx, project_folder)
)
commands.append(dct_sun.to_rad_string())
commands.append(
':: :: rmtxop -c 47.4 119.9 11.6 [sun results.rgb] ^> '
'[sun results.ill]'
)
commands.append('::')
finalmtx = rgb_matrix_file_to_ill(
(dct_sun.output_file,),
'result/sun..{}..{}.ill'.format(window_group.name, state.name), transpose
)
commands.append(finalmtx.to_rad_string())
commands.append(':: :: calculating final results')
commands.append(
':: :: rmtxop [3phase results.ill] - [direct results.ill] + '
'[sun results.ill] ^> [final results.ill]'
)
commands.append('::')
fmtx = final_matrix_addition(
'result/3phase..{}..{}.ill'.format(window_group.name, state.name),
'result/direct..{}..{}.ill'.format(window_group.name, state.name),
'result/sun..{}..{}.ill'.format(window_group.name, state.name),
'result/{}..{}.ill'.format(window_group.name, state.name)
)
commands.append(fmtx.to_rad_string())
commands.append(
':: end of calculation for {}, {}'.format(window_group.name, state.name))
commands.append('::')
commands.append('::')
results.append(
os.path.join(project_folder, str(fmtx.output_file))
)
return commands, results