Source code for raytraverse.integrator.helpers

# -*- coding: utf-8 -*-
# Copyright (c) 2020 Stephen Wasilewski, HSLU and EPFL
# =======================================================================
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# =======================================================================

"""parallelization functions for integration"""
import numpy as np

from raytraverse import io, translate
from raytraverse.mapper import ViewMapper
from raytraverse.sampler import SunSamplerPtView
from raytraverse.lightpoint import LightPointKD


[docs]def evaluate_pt(lpts, skyvecs, suns, vm=None, vms=None, metricclass=None, metrics=None, srconly=False, sumsafe=False, suntol=1.0, svengine=None, blursun=False, refl=None, resamprad=0.0, **kwargs): """point by point evaluation suitable for submitting to ProcessPool""" if len(lpts) == 0: return np.zeros((len(suns), len(vms), len(metrics))) if srconly or sumsafe: sunskypt = lpts smtx = skyvecs else: lp0 = lpts[0] for lp in lpts[1:]: lp0 = lp0.add(lp) sunskypt = [lp0] smtx = [np.hstack(skyvecs)] if len(vms) == 1: args = (vms[0].dxyz, vms[0].viewangle*vms[0].aspect) didx = [lpt.query_ball(*args)[0] for lpt in sunskypt] else: didx = [None]*len(sunskypt) srcs = [] resampi, resampvecs = prep_resamp(sunskypt, refl, resamprad) # loop over lightpoints to sum for ri, (lpt, di, sx) in enumerate(zip(sunskypt, didx, smtx)): pts = [] t_srcview = (lpt.srcviews, lpt.srcviewidxs) # loop over skyvecs to evaluate for skyvec, sun in zip(sx, suns): if svengine is not None and ri == resampi: update_src_view(svengine, lpt, sun[0:3], vm, suntol, refl=refl, resampvecs=resampvecs, resamprad=resamprad) vol = lpt.evaluate(skyvec, vm=vm, idx=di, blursun=blursun, srconly=srconly) views = [] for v in vms: views.append(metricclass(*vol, v, metricset=metrics, **kwargs)()) views = np.stack(views) pts.append(views) lpt.set_srcviews(*t_srcview) srcs.append(np.stack(pts)) return np.sum(srcs, axis=0)
[docs]def img_pt(lpts, skyvecs, suns, vms=None, combos=None, qpts=None, skinfo=None, res=512, interp=False, prefix="img", suntol=1.0, svengine=None, refl=None, resamprad=0.0, **kwargs): """point by point evaluation suitable for submitting to ProcessPool""" outfs = [] lpinfo = ["LPOINT{}= loc: ({:.3f}, {:.3f}, {:.3f}) src: ({:.3f}, {:.3f}, " "{:.3f}) {}".format(i, *lpt.pt, *lpt.srcdir[0], lpt.file) for i, lpt in enumerate(lpts)] if interp: lp0 = lpts[0] for lp in lpts[1:]: lp0 = lp0.add(lp) lpts = [lp0] skyvecs = [np.hstack(skyvecs)] vinfos = [] for i, v in enumerate(vms): img, pdirs, mask, mask2, header = v.init_img(res, jitter=.5, features=lpts[0].features) if interp == "highc": lp_is, w = lpts[0].interp(pdirs[mask], rt=svengine, **kwargs) lp_is = (lp_is,) elif interp == "high": lp_is, w = lpts[0].interp(pdirs[mask], **kwargs) lp_is = (lp_is,) elif interp == "fastc": lp_is, w = lpts[0].interp(pdirs[mask], angle=False, lum=False, dither=False, rt=svengine, **kwargs) lp_is = (lp_is,) elif interp == "fast": lp_is, w = lpts[0].interp(pdirs[mask], angle=False, lum=False, dither=False, **kwargs) lp_is = (lp_is,) elif interp: lp_is = [None] * len(lpts) w = None else: lp_is = [lpt.query_ray(pdirs[mask])[0] for lpt in lpts] w = None vinfos.append((i, v, img, pdirs, mask, mask2, lp_is, w)) if interp in ['high', 'fast', 'highc', 'fastc']: interp = 'precomp' resampi, resampvecs = prep_resamp(lpts, refl, resamprad) for j, (c, info, qpt, sun) in enumerate(zip(combos, skinfo, qpts, suns)): for i, v, img, pdirs, mask, mask2, lp_is, w in vinfos: header = [v.header(qpt), "SKYCOND= sunpos: ({:.3f}, {:.3f}, {:.3f})" " dirnorm: {} diffhoriz: {}".format(*info)] + lpinfo for ri, (lp_i, lp, svec) in enumerate(zip(lp_is, lpts, skyvecs)): if svengine is not None and ri == resampi: update_src_view(svengine, lp, sun[0:3], v, suntol, refl=refl, resampvecs=resampvecs, resamprad=resamprad) lp.add_to_img(img, pdirs[mask], mask2, vm=v, interp=interp, idx=lp_i, skyvec=svec[j], engine=svengine, interpweights=w) if np.min(svec) < 0: img = np.maximum(img, 0) outf = "{}_{}_{}_{}.hdr".format(prefix, *c[i]) outfs.append(outf) io.array2hdr(img, outf, header) img[:] = 0 return outfs
[docs]def prep_ds(lpts, skyvecs): try: snp = lpts[2] except IndexError: # this implies the sunpt is not needed (0 direct solar) return lpts[0:1], skyvecs[0:1], None skyvecs = [np.hstack(skyvecs[0:2]), skyvecs[2]] ski, skyvecs, refl = apply_dsky_patch(lpts[0], lpts[1], skyvecs, snp.srcdir) lpts = [ski, snp] return lpts, skyvecs, refl
[docs]def evaluate_pt_ds(lpts, skyvecs, suns, **kwargs): lpts, skyvecs, refl = prep_ds(lpts, skyvecs) return evaluate_pt(lpts, skyvecs, suns, refl=refl, **kwargs)
[docs]def img_pt_ds(lpts, skyvecs, suns, **kwargs): lpts, skyvecs, refl = prep_ds(lpts, skyvecs) return img_pt(lpts, skyvecs, suns, refl=refl, **kwargs)
def _prep_dv(lpts, skyvecs, skdir): dirlum = np.zeros((len(lpts[0].lum), 1)) ski, skyvecs, refl = apply_dsky_patch(lpts[0], lpts[1], skyvecs, skdir, dirlum) lpts = [ski] return lpts, skyvecs, refl
[docs]def evaluate_pt_dv(lpts, skyvecs, suns, **kwargs): side = int((skyvecs[0].shape[1] - 1)**.5) skpatch = translate.xyz2skybin(suns[0], side)[0] skdir = translate.skybin2xyz(skpatch, side)[0] lpts, skyvecs, refl = _prep_dv(lpts, skyvecs, skdir) kwargs.update(suntol=-1) return evaluate_pt(lpts, skyvecs, suns, refl=refl, **kwargs)
[docs]def img_pt_dv(lpts, skyvecs, suns, **kwargs): side = int((skyvecs[0].shape[1] - 1)**.5) skpatch = translate.xyz2skybin(suns[0], side)[0] skdir = translate.skybin2xyz(skpatch, side)[0] lpts, skyvecs, refl = _prep_dv(lpts, skyvecs, skdir) kwargs.update(suntol=-1) return img_pt(lpts, skyvecs, suns, refl=refl, **kwargs)
[docs]def prep_resamp(lpts, refl=None, resamprad=0.0): sunpt = [i for i, s in enumerate(lpts) if "_sun_" in s.src] sunpt2 = [i for i, s in enumerate(lpts) if "sun" in s.src] if len(sunpt) > 0: resampi = sunpt[0] elif len(sunpt2) > 0: resampi = sunpt2[0] else: resampi = -1 srcdir = lpts[resampi].srcdir[-1:] if refl is not None: refl = translate.norm(refl.reshape(-1, 3)) sunr = translate.reflect(srcdir, refl, False) srcdir = np.vstack((srcdir, sunr[0])) if resampi >= 0 and resamprad > 0.0: resampvecs = [] for src in srcdir: i = lpts[resampi].query_ball(src, resamprad) resampvecs.append(i[0]) else: resampvecs = None return resampi, resampvecs
def _in_view(vm, suna, sunb, tol=0.533): return (vm.degrees(suna)[0] <= (vm.viewangle + tol)/2 or vm.degrees(sunb)[0] <= (vm.viewangle + tol)/2)
[docs]def update_src_view(engine, lpt, sun, vm=None, tol=1.0, refl=None, resampvecs=None, reflarea=None, resamprad=0.0): rtol = max(0.533, resamprad) if translate.degrees(sun, lpt.srcdir)[0] <= tol: return None if reflarea is None: reflarea = [0.533] if vm is None: vm = ViewMapper() inview = [_in_view(vm, sun, lpt.srcdir[-1], rtol)] svm = [ViewMapper(sun, reflarea[0], "sunview")] srcdir = [sun] if refl is not None and len(refl) > 0: if len(reflarea) < 1 + len(refl): reflarea += [0.533]*len(refl) refl = translate.norm(refl.reshape(-1, 3)) sunr = translate.reflect(sun.reshape(1, 3), refl, False) for i, (sr, m, ar) in enumerate(zip(*sunr, reflarea[1:])): if m and ar > 0: rsrc = translate.reflect(lpt.srcdir[-1:], refl)[0][0] srcdir.append(rsrc) vm = ViewMapper(sr, ar, f"reflection_{i:03d}") svm.append(vm) inview.append(_in_view(vm, sr, rsrc, rtol)) dosamp = np.any(inview) if len(svm) > 0 and dosamp: viewsampler = SunSamplerPtView(lpt.scene, engine, sun, 0) svpoints = viewsampler.run(lpt.pt, 0, vm=svm) lpt.set_srcviews(svpoints) if resampvecs is not None and dosamp: vecs = [] ri = [] for sd, rs, iv, sv in zip(srcdir, resampvecs, inview, svm): if inview and len(rs) > 0: ymtx, pmtx = translate.rmtx_yp(np.stack((sd, sv.dxyz))) # rotate to z-up in lp.srcdir space vec = np.einsum("ij,kj,li->kl", ymtx[0], lpt.vec[rs], pmtx[0]) # rotate back in actual sun space vec = np.einsum("ji,kj,il->kl", pmtx[1], vec, ymtx[1]) lucky_squirel = sv.degrees(vec) > 0.534/2 if np.sum(lucky_squirel) > 0: vecs.append(vec[lucky_squirel]) ri.append(np.array(rs)[lucky_squirel]) if len(ri) > 0: rvecs = np.vstack(vecs) ris = np.concatenate(ri) rvecs = np.concatenate(np.broadcast_arrays(lpt.pt[None, :], rvecs), 1) lpt.lum[ris, -1] = engine(rvecs).ravel()
[docs]def apply_dsky_patch(skp, skd, skyvecs, skdir, dirlum=None): skpatch = translate.xyz2skybin(skdir, int((skp.srcn - 1)**.5))[0] skvec = skp.vec skydlum = np.copy(skd.lum[:, skpatch]) sklum = np.maximum((skp.lum[:, skpatch] - skydlum), 0)[:, None] sklum = np.hstack((skp.lum, sklum)) srcn = skp.srcn + 1 if len(skyvecs[0]) < sklum.shape[1]: sklum = np.einsum('ij,kj->ki', skyvecs[0], sklum) srcn = len(skyvecs[0]) skyvecs[0] = np.eye(len(skyvecs[0])) if dirlum is not None: srcn += 1 sklum = np.hstack((sklum, dirlum)) skyvecs = [np.hstack(skyvecs)] ski = LightPointKD(skp.scene, vec=skvec, lum=sklum, vm=skp.vm, pt=skp.pt, posidx=skp.posidx, src=f'sky_isun{skpatch:04d}', srcn=srcn, srcdir=skdir, write=False, omega=skp.omega, parent=skp.parent) try: refl = io.load_txt(f"{skp.scene.outdir}/{skp.parent}/" f"reflection_normals.txt") except FileNotFoundError: refl = None else: refl = translate.norm(refl.reshape(-1, 3)) return ski, skyvecs, refl