From 6c32b6c17a33663979ad3245151237c67c1c8961 Mon Sep 17 00:00:00 2001 From: taoning Date: Wed, 18 Sep 2024 15:51:07 -0700 Subject: [PATCH] fix(method): random name octree for edgps calc --- frads/methods.py | 150 +++++++++++++++++------------------------------ 1 file changed, 53 insertions(+), 97 deletions(-) diff --git a/frads/methods.py b/frads/methods.py index f011930..49730eb 100755 --- a/frads/methods.py +++ b/frads/methods.py @@ -1,5 +1,4 @@ -"""Typical Radiance matrix-based simulation workflows -""" +"""Typical Radiance matrix-based simulation workflows""" import hashlib import logging @@ -15,14 +14,30 @@ from pyradiance.util import parse_view from scipy.sparse import csr_matrix -from frads.matrix import (BASIS_DIMENSION, Matrix, SensorSender, SkyReceiver, - SunMatrix, SunReceiver, SurfaceReceiver, - SurfaceSender, ViewSender, load_binary_matrix, - load_matrix, matrix_multiply_rgb, - sparse_matrix_multiply_rgb_vtds, to_sparse_matrix3) +from frads.matrix import ( + BASIS_DIMENSION, + Matrix, + SensorSender, + SkyReceiver, + SunMatrix, + SunReceiver, + SurfaceReceiver, + SurfaceSender, + ViewSender, + load_binary_matrix, + load_matrix, + matrix_multiply_rgb, + sparse_matrix_multiply_rgb_vtds, + to_sparse_matrix3, +) from frads.sky import WeaData, WeaMetaData, gen_perez_sky, parse_epw, parse_wea -from frads.utils import (minutes_to_datetime, parse_polygon, parse_rad_header, - polygon_primitive, random_string) +from frads.utils import ( + minutes_to_datetime, + parse_polygon, + parse_rad_header, + polygon_primitive, + random_string, +) logger: logging.Logger = logging.getLogger("frads.methods") @@ -113,14 +128,8 @@ def __post_init__(self): for k, v in self.matrices.items(): if isinstance(v, dict): self.matrices[k] = MatrixConfig(**v) - if ( - self.bytes == b"" - and len(self.files) == 0 - and len(self.matrices) == 0 - ): - raise ValueError( - "MaterialConfig must have either file, bytes or matrices" - ) + if self.bytes == b"" and len(self.files) == 0 and len(self.matrices) == 0: + raise ValueError("MaterialConfig must have either file, bytes or matrices") @dataclass @@ -195,8 +204,7 @@ def __post_init__(self): if self.file != "": with open(self.file) as f: self.data = [ - [float(i) for i in line.split()] - for line in f.readlines() + [float(i) for i in line.split()] for line in f.readlines() ] else: raise ValueError("SensorConfig must have either file or data") @@ -270,9 +278,7 @@ def __post_init__(self): if self.file.exists() and len(self.primitives) == 0: self.primitives = pr.parse_primitive(self.file.read_text()) elif len(self.primitives) == 0: - raise ValueError( - "SurfaceConfig must have either file or primitives" - ) + raise ValueError("SurfaceConfig must have either file or primitives") @dataclass @@ -459,15 +465,10 @@ def __post_init__(self): ]: continue else: - raise ValueError( - f"Sensor {k} data does not match view {k} data" - ) + raise ValueError(f"Sensor {k} data does not match view {k} data") else: self.sensors[k] = SensorConfig( - data=[ - self.views[k].view.position - + self.views[k].view.direction - ] + data=[self.views[k].view.position + self.views[k].view.direction] ) for k, v in self.windows.items(): @@ -515,9 +516,7 @@ def __post_init__(self): self.settings = Settings(**self.settings) if isinstance(self.model, dict): self.model = Model(**self.model) - self.hash_str = hashlib.md5(str(self.__dict__).encode()).hexdigest()[ - :16 - ] + self.hash_str = hashlib.md5(str(self.__dict__).encode()).hexdigest()[:16] @staticmethod def from_dict(obj: Dict[str, Any]) -> "WorkflowConfig": @@ -587,16 +586,12 @@ def __init__(self, config: WorkflowConfig): with open(self.config.settings.epw_file) as f: self.wea_metadata, self.wea_data = parse_epw(f.read()) self.wea_header = self.wea_metadata.wea_header() - self.wea_str = self.wea_header + "\n".join( - str(d) for d in self.wea_data - ) + self.wea_str = self.wea_header + "\n".join(str(d) for d in self.wea_data) elif self.config.settings.wea_file != "": with open(self.config.settings.wea_file) as f: self.wea_metadata, self.wea_data = parse_wea(f.read()) self.wea_header = self.wea_metadata.wea_header() - self.wea_str = self.wea_header + "\n".join( - str(d) for d in self.wea_data - ) + self.wea_str = self.wea_header + "\n".join(str(d) for d in self.wea_data) else: if ( self.config.settings.latitude is None @@ -689,11 +684,7 @@ def get_sky_matrix( and isinstance(dhi, (float, int)) ): _wea += str(WeaData(time, dni, dhi)) - elif ( - isinstance(time, list) - and isinstance(dni, list) - and isinstance(dhi, list) - ): + elif isinstance(time, list) and isinstance(dni, list) and isinstance(dhi, list): rows = [str(WeaData(t, n, d)) for t, n, d in zip(time, dni, dhi)] _wea += "\n".join(rows) _ncols = len(time) @@ -716,9 +707,7 @@ def get_sky_matrix( dtype="d", ) - def get_sky_matrix_from_wea( - self, mfactor: int, sun_only=False, onesun=False - ): + def get_sky_matrix_from_wea(self, mfactor: int, sun_only=False, onesun=False): if self.wea_str is None: raise ValueError("No weather string available") _sun_str = pr.gendaymtx( @@ -741,9 +730,7 @@ def get_sky_matrix_from_wea( daylight_hours_only=True, mfactor=mfactor, ) - _nrows, _ncols, _ncomp, _dtype = parse_rad_header( - pr.getinfo(_matrix).decode() - ) + _nrows, _ncols, _ncomp, _dtype = parse_rad_header(pr.getinfo(_matrix).decode()) return load_binary_matrix( _matrix, nrows=_nrows, @@ -835,9 +822,7 @@ def calculate_view( A image as a numpy array """ sky_matrix = self.get_sky_matrix(time, dni, dhi) - return matrix_multiply_rgb( - self.view_sky_matrices[view].array, sky_matrix - ) + return matrix_multiply_rgb(self.view_sky_matrices[view].array, sky_matrix) def calculate_sensor( self, sensor: str, time: datetime, dni: float, dhi: float @@ -913,9 +898,7 @@ def calculate_sensor_from_wea(self, sensor: str) -> np.ndarray: raise ValueError("No wea data available") return matrix_multiply_rgb( self.sensor_sky_matrices[sensor].array, - self.get_sky_matrix_from_wea( - int(self.config.settings.sky_basis[-1]) - ), + self.get_sky_matrix_from_wea(int(self.config.settings.sky_basis[-1])), weights=[47.4, 119.9, 11.6], ) @@ -952,8 +935,7 @@ def __init__(self, config): pr.oconv( *config.model.materials.files, *config.model.scene.files, - stdin=config.model.materials.bytes - + config.model.scene.bytes, + stdin=config.model.materials.bytes + config.model.scene.bytes, ) ) self.window_senders: Dict[str, SurfaceSender] = {} @@ -1080,9 +1062,7 @@ def calculate_view( res = [] if isinstance(bsdf, list): if len(bsdf) != len(self.config.model.windows): - raise ValueError( - "Number of BSDF should match number of windows." - ) + raise ValueError("Number of BSDF should match number of windows.") for idx, _name in enumerate(self.config.model.windows): _bsdf = bsdf[idx] if isinstance(bsdf, list) else bsdf res.append( @@ -1118,13 +1098,9 @@ def calculate_sensor( res = [] if isinstance(bsdf, list): if len(bsdf) != len(self.config.model.windows): - raise ValueError( - "Number of BSDF should match number of windows." - ) + raise ValueError("Number of BSDF should match number of windows.") for idx, _name in enumerate(self.config.model.windows): - _bsdf = self.config.model.materials.matrices[ - bsdf[_name] - ].matrix_data + _bsdf = self.config.model.materials.matrices[bsdf[_name]].matrix_data res.append( matrix_multiply_rgb( self.sensor_window_matrices[sensor].array[idx], @@ -1237,13 +1213,9 @@ def calculate_surface( sky_matrix = self.get_sky_matrix( time, dni, dhi, solar_spectrum=solar_spectrum ) - res = np.zeros( - (self.surface_senders[surface].yres, sky_matrix.shape[1]) - ) + res = np.zeros((self.surface_senders[surface].yres, sky_matrix.shape[1])) for idx, _name in enumerate(self.config.model.windows): - _bsdf = self.config.model.materials.matrices[ - bsdf[_name] - ].matrix_data + _bsdf = self.config.model.materials.matrices[bsdf[_name]].matrix_data res += matrix_multiply_rgb( self.surface_window_matrices[surface].array[idx], _bsdf, @@ -1293,14 +1265,12 @@ def calculate_edgps( gmaterial = _gms[sname] stdins.append(gmaterial.bytes) for prim in self.window_senders[wname].surfaces: - stdins.append( - replace(prim, modifier=gmaterial.identifier).bytes - ) + stdins.append(replace(prim, modifier=gmaterial.identifier).bytes) if (_pgs := self.config.model.windows[wname].proxy_geometry) != {}: for prim in _pgs[sname]: stdins.append(prim.bytes) - octree = "test.oct" + octree = f"{random_string(5)}.oct" with open(octree, "wb") as f: f.write(pr.oconv(stdin=b"".join(stdins), octree=self.octree)) @@ -1385,9 +1355,7 @@ def __init__(self, config: WorkflowConfig): pr.oconv( *config.model.materials.files, *config.model.scene.files, - stdin=( - config.model.materials.bytes + config.model.scene.bytes - ), + stdin=(config.model.materials.bytes + config.model.scene.bytes), ) ) self.blacked_out_octree: Path = self.octdir / f"{random_string(5)}.oct" @@ -1425,9 +1393,7 @@ def _gen_blacked_out_octree(self): pr.xform(s, modifier="black") for s in self.config.model.scene.files ) if self.config.model.scene.bytes != b"": - black_scene += pr.xform( - self.config.model.scene.bytes, modifier="black" - ) + black_scene += pr.xform(self.config.model.scene.bytes, modifier="black") black = pr.Primitive("void", "plastic", "black", [], [0, 0, 0, 0, 0]) glow = pr.Primitive("void", "glow", "glowing", [], [1, 1, 1, 0]) with open(self.blacked_out_octree, "wb") as f: @@ -1531,9 +1497,7 @@ def _prepare_sun_receivers(self): parse_polygon(r.surfaces[0]).normal.tobytes() for r in self.window_receivers.values() ] - unique_window_normals = [ - np.frombuffer(arr) for arr in set(window_normals) - ] + unique_window_normals = [np.frombuffer(arr) for arr in set(window_normals)] self.sensor_sun_receiver = SunReceiver( self.config.settings.sun_basis, sun_matrix=self.direct_sun_matrix, @@ -1585,14 +1549,10 @@ def _prepare_mapping_octrees(self): blacked_out_windows = str(black) + " ".join(blacked_out_windows) glowing_windows = str(glow) + " ".join(glowing_windows) with open(self.vmap_oct, "wb") as wtr: - wtr.write( - pr.oconv(stdin=glowing_windows.encode(), octree=self.octree) - ) + wtr.write(pr.oconv(stdin=glowing_windows.encode(), octree=self.octree)) logger.info("Generating view matrix material map octree") with open(self.cdmap_oct, "wb") as wtr: - wtr.write( - pr.oconv(stdin=blacked_out_windows.encode(), octree=self.octree) - ) + wtr.write(pr.oconv(stdin=blacked_out_windows.encode(), octree=self.octree)) def generate_matrices(self): if self.mfile.exists(): @@ -1731,9 +1691,7 @@ def calculate_sensor_from_wea(self, sensor): ) direct_sky_matrix = to_sparse_matrix3(direct_sky_matrix) res3 = np.zeros((self.sensor_senders[sensor].yres, sky_matrix.shape[1])) - res3d = np.zeros( - (self.sensor_senders[sensor].yres, sky_matrix.shape[1]) - ) + res3d = np.zeros((self.sensor_senders[sensor].yres, sky_matrix.shape[1])) for idx, _name in enumerate(self.config.model.windows): res3 += matrix_multiply_rgb( self.sensor_window_matrices[sensor].array[idx], @@ -1749,9 +1707,7 @@ def calculate_sensor_from_wea(self, sensor): direct_sky_matrix, weights=[47.4, 119.9, 11.6], ) - rescd = np.zeros( - (self.sensor_senders[sensor].yres, sky_matrix.shape[1]) - ) + rescd = np.zeros((self.sensor_senders[sensor].yres, sky_matrix.shape[1])) for c, w in enumerate([47.4, 119.9, 11.6]): rescd += w * np.dot( self.sensor_sun_direct_matrices[sensor].array[c],