guv-calcs v0.7.3: An open-source Python library for modeling germicidal UV in indoor environments
Abstract
guv-calcs is an open-source Python scientific computing library for physically based modeling of germicidal ultraviolet (GUV) light in indoor environments, with a focus on far-UVC (200–235 nm) applications. The library provides core numerical tools for representing lamps, spatial geometry, calculation planes and volumes, and exposure metrics such as irradiance, fluence rate, and cumulative dose. The package implements vectorized radiative transfer calculations using measured photometric data (IES/ULD files), supports flexible three-dimensional room geometries, and is designed for integration with higher-level tools such as visualization dashboards, airflow models, and risk frameworks for airborne pathogen control. The codebase emphasizes reproducibility, transparency, and modularity so that researchers, engineers, and manufacturers can inspect, extend, and validate the underlying calculations. guv-calcs forms the computational backbone of the broader Illuminate ecosystem, but is usable as a standalone library for custom analyses, batch simulations, and method development. The project aims to improve rigor and accessibility in far-UVC modeling by providing a free, auditable, and community-maintained alternative to proprietary software. v0.7.3 Release Notes Added Room.set_dimensions() accepts polygon=; Room.set_polygon() sets the floor plan after construction. Passing x/y to a polygon room converts it back to a rectangle generate_report() lists every floor plan vertex for polygon rooms and reports floor area for all rooms Fixed generate_report() reflectance header was hardcoded to Floor/Ceiling/North/South/East/West, which mislabeled the wall columns (values are ordered south/east/north/west) and didn't fit polygon rooms' wall_N surfaces; labels now come from the room's actual surfaces Changing a room's floor plan left stale wall surfaces behind (e.g. wall_5 after going from 6 walls to 5, or wall_N alongside cardinal names after going back to a rectangle); surfaces are now rebuilt from the new faces, with reflectance, transmittance and grid resolution carried over by edge index across the cardinal/wall_N renaming Standard zones ignored floor plan changes (SurfaceGrid.update_dimensions() is a no-op for polygon grids); Room._resize_standard_zones() now rebuilds them from the polygon, keeping spacing/num_points and plane height Room floor plans accepted degenerate outlines; coincident consecutive vertices or zero area now raise ValueError (RoomDimensions), and Polygon2D rejects non-finite or non-pair vertices