Skip to main content

Algorithmic Cooling (MSc)

Page 1

ALGORITHMIC COOLING A I - P O W E R E D U R B A N FA Ç A D E A N A LY T I C S

2025 / 2026

Sara Nisavic (M.Sc) Apoorva (M.Arch) Ting-Yu Lee (Calvin) (M.Arch)


Founding Director Dr. Michael Weinstock

Course Director Dr. Milad Showkatbakhsh

Studio Master Dr. Anna Font

Studio Tutors Abhinav Chaudhary Paris Nikitidis Krishna Bhat Danae Polyviou Dr. Alvaro Velasco Perez


ARCHITECTURAL ASSOCIATION SCHOOL OF ARCHITECTURE GRADUATE SCHOOL PROGRAMMES PROGRAMME:

EMERGENT TECHNOLOGIES AND DESIGN

YEAR:

2025-2026

COURSE TITLE:

MSc. Dissertation

DISSERTATION TITLE:

Algorithmic Cooling

STUDENT NAMES:

Sara Nisavic (M.Sc)

Ting-Yu Lee (Calvin) (M.Arch) Apoorva (M.Arch) DECLARATION: “I certify that this piece of work is entirely my/our and that my quotation or paraphrase from the published or unpublished work of other is duly acknowledged.”

SIGNATURE OF THE STUDENT:

Date: 18 September 2026


Acknowledgements We would like to express our deepest gratitude to Founding Director Dr. Michael Weinstock, whose work on urban morphology and climate provided a profound theoretical foundation for our investigation into the Urban Heat Island effect. Our sincere thanks also go to Course Director Dr. Milad Showkatbakhsh for his invaluable technical mentorship. His strategic advice on computational workflows and his continuous support fundamentally guided the technical development of this dissertation. We are profoundly grateful to our Studio Master, Dr. Anna Font, for her rigorous critique. Her guidance was essential in translating complex computational data into clear, user-centric visualizations with tangible architectural applications. We also extend our appreciation to our exceptional Studio Tutors: Abhinav Chaudhary, Paris Nikitidis, Krishna Bhat, Danae Polyviou, and Dr. Alvaro Velasco Perez for their technical expertise and steadfast support throughout our research. Finally, our heartfelt thanks go to our families, friends, and EmTech colleagues. Their unwavering encouragement, boundless patience, and continuous moral support provided the fundamental anchor that made completing this journey possible for all of us.


Abstract As Urban Heat Island (UHI) effects intensify, mitigating street-level heat has become a critical challenge for urban resilience. However, current research relies mostly on horizontal satellite data, ignoring the thermal impact of vertical surface materials, while most design tools are either too slow for urban-scale analysis or incapable of simulating vertical surfaces. Consequently, the thermal impact of vertical envelopes remains unmapped, leaving planners without an accessible workflow to evaluate material choices during early design phases. This project presents Algorithmic Cooling, an AI-driven urban data processing pipeline and a hermal analytic portal developed to bridge this data gap. Our methodology employs computer vision and visionlanguage models (VLMs) to automatically recognize facade materials and map them to spatial geometries using uncurated street-level imagery. This multi-stage filtering and segmentation process structures pixel-level data into a granular, 3D city-scale material database. The extracted data feeds a machine learning surrogate model, trained on robust environmental simulations, to instantly predict hourly surface temperatures and thermal radiation flux within street canyons. The deployed web portal couples these spatial databases directly with the surrogate engine, transforming abstract thermal calculations into intuitive decision-support analytics. Through interactive 3D visualizations, users can evaluate localized heat loads, modify facade material specifications, and immediately assess microclimatic impacts. Together, Algorithmic Cooling establishes an operational, scalable framework for integrating thermodynamic performance into climate-responsive urban design and planning practice.


Contents

Contents 01 Introduction 2

03 Method 34

1.1 The Escalating Urban Heat Crisis

4

3.1 Overall Framework

36

1.2 Urban Heat Island in London

2

3.2 Thermal Simulation

38

1.3 Adaptation to Extreme Heat

4

3.3 Data Acquisition & Post Process Pipeline

40

3.4 Analytic Portal

44

02 Domain 6

viii

2.1 Urban Heat Island

8

2.2 The Physics

12

4.1 Field Study

48

2.3 The horizontal Bias of Remote Sensing

16

4.2 Digital Experiments

50

2.4 Urban-Scale Thermal Analysis

24

4.2.6 Conclusion

60

2.5 Design Problem Synthesis

32

4.3 Identifying and Mitigating Data Noise

62

2.6 Research Question

33

04 Research Developement 46


05 Design Development 72

07 Conclusion

146

5.1 Surrogate Model

74

7.1 Discussion and Future Work

148

5.2 Material Data Acquisition

86

7.2 Conclusion

150

Bibliography 152

06 Design Proposal

104

6.1 The Analytic Portal

106

6.2 Step 1: Query Facade Data

114

6.3 Step 2: Predict & Calculate Heat

118

6.4 Step 3: Visualise in 3D

122

6.5 Step 4: Identify Heat Zones

126

6.6 Step 5: Make a Change

134

6.7 Step 6: Compare Impact

136

6.8 Experiment : Material Thermal Impact

138

Appendix 156

ix


01 Introduction The Urban Heat Island (UHI) effect has emerged as one of today’s most pressing global challenges, defined by the severe elevation of urban temperatures compared to surrounding rural landscapes. Compounded by the increasing frequency of extreme climate events, UHI acts as a threat multiplier, severely degrading urban liability. Driven by irreversible global warming and continued urbanization, future architectural and urban frameworks must urgently prioritize heat adaptation and UHI mitigation.


Fig. 1.3 Caption set small and grey in the narrow inner column, beneath its figure.

3


1.1 The Escalating Urban Heat Crisis

Rather than a static collection of buildings, the city can be understood as an organism-like metabolic system, consisting of layers of energy flows including energy, material, micro-climate, human activity, and many more. However, urban ecology is currently under severe strain in recent years. Due to global warming, the mean annual temperatures in 2025 have already reached approximately 1.5°C above the preindustrial average, breaking the Paris Agreement thresholds.1 When combined with the Urban Heat Island (UHI) effect, which is generated by high-density, non-porous, and heat-storing urban fabrics, it creates a lethal compound multiplier that further heat up the urban spaces.

Fig. 1.1.1 Global heat-related mortality trends (1990–2020). The chart illustrates annual deaths (dashed red) against a 10-year moving average (solid black). While massive mortality spikes correlate with specific localized extreme events (e.g., the 2003 European and 2010 Russian heatwaves), the steady upward trajectory of the 10-year average demonstrates the escalating, long-term lethality of global temperature rise.

While disasters like hurricanes, floods, and tornadoes command significant media attention due to their immediate destruction, extreme heat is far deadlier than all of them combined.2 According to The Lancet, nearly 489,000 people die annually from heat-related causes, with UHI-specific factors contributing significantly to premature mortality in dense cities.3 With 56% of the global population (projected to reach 68% by 2050) now residing in urban areas,4 the survival of the next generation depends on our ability to identify systemic urban failures and to design new cities for ecological resilience.

800K

600K

400K

200K

0K 1990

1995

2000

2005

2010

2015

2020

1 Marina Romanello, Maria Walawender, Shih-Che Hsu, Annalyse Moskeland, Yasna Palmeiro-Silva, Daniel Scamman, James W. Smallcombe, et al., “The 2025 Report of the Lancet Countdown on Health and Climate Change: Climate Change Action Offers a Lifeline,” The Lancet 406, no. 10521 (2025): 2804, https:// doi.org/10.1016/S0140-6736(25)01919-1. 2 Terri Adams-Fuller, “Dangerous Discomfort,” Scientific American 329, no. 1 (July/August 2023): 64, https:// doi.org/10.1038/scientificamerican0723-64. 3 Romanello et al., “The 2025 Report of the Lancet Countdown on Health and Climate Change,” 2804. 4 United Nations Human Settlements Programme (UN-Habitat), World Cities Report 2022: Envisaging the Future of Cities (Nairobi: UN-Habitat, 2022), xxi.

4

ALGORITHMIC COOLING


Fig. 1.1.2: Comparative global thermal mapping. Heatmap visualizations contrasting historical temperature averages (top) with the extreme anomalies of 2023 (bottom). This macro-level escalation of global warming acts as a lethal multiplier for localized Urban Heat Island (UHI) effects in dense metropolitan areas. (Data source: Google Earth).

1990

2C 1C 0C -1 C -2 C

01 I N T R O D U C T I O N

2023

5


1.2 Urban Heat Island in London

London occupies a singular position in the history and present of urban climatology. It is the city in which the phenomenon was first documented: Luke Howard’s 1833 study of London’s climate is widely credited as the founding observation of what would later be termed the urban heat island.1 Two centuries later, London remains one of the most severe contemporary UHI hotspots: Arup’s Urban Heat Snapshot survey found London’s dense urban core up to 4.5°C warmer than its surrounding rural areas under extreme conditions.2 Combined with a highly heterogeneous urban fabric — a patchwork of Georgian brick terraces, Victorian stock, mid-century concrete estates, and contemporary glazed towers — London offers both an acute case study and an unusually rich natural laboratory for investigating how material and morphology interact to produce heat. The human cost is not speculative. A 2015 mapping study attributed an estimated 274 heat-related deaths across London to elevated urban temperatures during a single summer, with mortality tracking the intensity and geography of the UHI effect.3 Comparable summers are projected to become the UK norm by mid-century,4 turning what is now framed as an exceptional event into an ordinary design condition that London’s building stock will need to withstand.

Fig. 1.2 Median summer Land Surface Temperature (LST) distribution in London (20192024, Jun-Aug). (Map generated by the author using Landsat 8 Level-2 data via Google Earth Engine.)

1 Luke Howard, The Climate of London: Deduced from Meteorological Observations Made at Different Places in the Neighbourhood of the Metropolis, 3 vols. (London: Harvey and Darton, 1833). 2 Arup, Urban Heat Snapshot (London: Arup, July 2024). 3 Jonathon Taylor et al., “Mapping the Effects of Urban Heat Island, Housing, and Age on Excess HeatRelated Mortality in London,” Urban Climate 14 (2015): 517–528. 4 Met Office, “UK and Global Extreme Events – Heatwaves,” accessed July 2026.

2

ALGORITHMIC COOLING


01 I N T R O D U C T I O N

3


1.3 Adaptation to Extreme Heat The Urban Heat Island (UHI) effect represents an unresolved global concern that commands sustained research, reflected in 9,061 Web of Science publications recorded between 2004 and 2024, peaking in 2020 to 2022.1 Within urban planning and architectural design, the question is no longer whether UHI is a severe threat, as literature has firmly confirmed its risks, but whether designers possess the knowledge, data, and workflows needed to assess an envelope’s thermal impact at a city scale. As cities increasingly face severe heatwaves, relying on sealed building envelopes and air conditioning merely exacerbates the UHI effect. Future architecture must disrupt this destructive loop, adapting to climatic extremes while minimizing heat rejection into the urban environment.

1 Murat Kilinc et al., “Exploring the Urban Heat Island Effect: A Bibliometric and Topic Modeling Analysis,” Sustainability 17, no. 17 (2025): 8072, https://doi.org/10.3390/su17178072.

4

ALGORITHMIC COOLING


Fig. 1.3 A reference image showcasing dense urban structures under the sun. (Photo by Dajana Reçi via Pexels)

01 I N T R O D U C T I O N

5


02 Domain Surface Urban Heat Island (SUHI) is one of the mainstream approaches in UHI research, relying heavily on remote sensing technology to investigate horizontal surface temperature data. Through this reliance, the team identified an observational bias: most research and planning have remained horizontally focused, resulting in a data gap on urban vertical surfaces. As a result, the thermal impact of urban vertical surfaces remains unmapped due to both a data gap and an analysis-tool gap. Today, with emerging technology, this project explores novel methodologies to map the relationship between vertical surfaces and their thermal behaviour.

Fig. 2 Radial dendrogram detailing the causal drivers of the Urban Heat Island (UHI) effect. The diagram hierarchically maps the root causes of urban warming across four primary thermodynamic categories: Anthropogenic Heat, Net Radiation & Storage, Latent Heat, and Sensible Heat.


7


2.1 Urban Heat Island

2.1.1 Defination The Urban Heat Island effect describes the temperature difference between an urban area and its surrounding rural environment. It results from changes in land cover, surface characteristics and human activity associated with urbanisation. Cities contain extensive impervious surfaces, including concrete, brick, stone and asphalt, which absorb and retain more heat than vegetation and soil. Reduced vegetation also limits cooling through evapotranspiration, producing a distinct urban thermal environment.1 2.1.2 Factors contributing to UHI The Urban Heat Island effect is influenced by latent, sensible and anthropogenic heat. These processes relate to evapotranspiration, heat transfer from urban surfaces and heat released by buildings, transport and other human activities.2 Within architectural design, this research focuses on two controllable factors: urban materials and urban morphology. Material properties govern the absorption, reflection, storage and release of heat, while urban form controls solar exposure, shading and airflow within the urban canyon.3

1 L. W. A. van Hove et al., Exploring the Urban Heat Island Intensity of Dutch Cities: Assessment Based on a Literature Review, Recent Meteorological Observations and Datasets Provided by Hobby Meteorologists (Wageningen: Alterra, 2011), 13, 28. 2 Evyatar Erell, David Pearlmutter, and Terry Williamson, Urban Microclimate: Designing the Spaces Between Buildings (London: Earthscan, 2011), 27–84. 3 Evyatar Erell, David Pearlmutter, and Terry Williamson, Urban Microclimate: Designing the Spaces Between Buildings (London: Earthscan, 2011), 27–84.

8

Fig. 2.1.1 Ilustration showing UHI in Rural and urban context.

ALGORITHMIC COOLING


su

rf

d

ac

e

So

la

r

Ra

di

ct

at

ge po

St

iv

or

it

io

n

ro

te

at

du

th

fle c

He

co

ag

y,

An

by

Re

ni

c

He

at

Incoming Radiation

e/

he

at

Reflected Solar Radiation ca

pa

ci

ty

Day

N

n

atio

adi ET R

Evaporation/

RURAL

URBAN Night

latent heat

se

Co

nv

ns

ib

ec

le

ti

on

/

he

at

flu

x

Greenhouse gases

02 D O M A I N

9


2.1.3 Scale of Investigation Moreover, the city is experienced primarily within the urban canyon, which therefore forms the principal scale of this investigation. Material properties do not operate under isolated, free-field conditions but interact with canyon geometry and neighbouring surfaces. In dense canyons, a façade may have greater visual exposure to surrounding walls than to the sky, making radiation reflected and emitted by opposing façades an important component of the local thermal environment.1 These exchanges are examined through the Urban Surface Energy Balance, which describes how energy is received, reflected, absorbed, stored, and released by urban surfaces.2 The canyon scale is therefore essential for evaluating the combined influence of urban materials and geometry on pedestrian thermal exposure.

Fig. 2.1.3 Illustration showing the heat interaction o urban scale.

1 Evyatar Erell, David Pearlmutter, and Terry Williamson, Urban Microclimate: Designing the Spaces Between Buildings (London: Earthscan, 2011), 15–26. 2 Manuel Nunez and T. R. Oke, “The Energy Balance of an Urban Canyon,” Journal of Applied Meteorology 16, no. 1 (1977): 11–19.

10

ALGORITHMIC COOLING


(a)

(b)

Fig. 2.1.3 a) Heat map by google earth engine b) Thermal scan of a neighbourhood in london taken by the author

In dense urban canyons, vertical façades may constitute a greater proportion of the total exposed urban surface area than horizontal surfaces. Voogt and Oke found that vertical surfaces accounted for 54 per cent of the urban surface area within a dense study area, compared with 46 per cent represented by horizontal surfaces.1

1 James A. Voogt and T. R. Oke, “Complete Urban Surface Temperatures,” Journal of Applied Meteorology 36, no. 9 (1997): 1117–32.

02 D O M A I N

11


2.2 The Physics

2.2.1 Surface Energy Balance The urban surface energy balance is based on the first law of thermodynamics, which states that energy can neither be created nor destroyed but can only be transformed from one form to another. When solar radiation reaches an urban surface, part of it is reflected, while the remainder is absorbed. A proportion of the absorbed energy is stored within the material and later released into the surrounding environment through convection and longwave radiation. The amount and timing of this release depend on the radiative and thermal properties of the material.1

SURFACE ENERGY BALANCE Q*net = Rin - Rout

Rin depend on the geometry Rout depends on the material

Rout = Reflection+ Emission

Within an urban canyon, these processes are influenced by the interaction between the ground, façades, sky, and adjacent buildings. Canyon geometry modifies solar exposure and radiative exchange, while material properties determine the response of individual surfaces. The urban canyon therefore provides an appropriate scale for assessing the combined influence of morphology and materials on urban heat and pedestrian radiant exposure.2

Reflection: Urban Surfaces receives and reflect solar radiation.

Stored: Urban Surfaces absorbs solar radiation.

1 Manuel Nunez and T. R. Oke, “The Energy Balance of an Urban Canyon,” Journal of Applied Meteorology 16, no. 1 (1977): 11–19. 2 Evyatar Erell, David Pearlmutter, and Terry Williamson, Urban Microclimate: Designing the Spaces Between Buildings (London: Earthscan, 2011), 15–26.

12

Emission: Urban Surfaces releases back radiations. ALGORITHMIC COOLING


2.2.2 Mean Radiant Temperature The radiant environment produced by urban surfaces and canyon geometry directly influences the heat experienced by pedestrians. Mean radiant temperature (MRT) represents the combined shortwave and longwave radiation received by the human body from the sun, sky, ground, and surrounding façades. It is therefore an important measure for evaluating how the thermal behaviour of an urban canyon affects human heat exposure and outdoor thermal comfort.1

Fig. 2.2.2 Ilustration showing surface energy balance.

02 D O M A I N

1 Evyatar Erell, David Pearlmutter, and Terry Williamson, Urban Microclimate: Designing the Spaces Between Buildings (London: Earthscan, 2011), 109–24.

13


2.2.3 Case Study: Shiraz Facade Materials1 Method and Findings:

1. Brick-Cream

Tabatabaei and Fayaz investigated the thermal performance of twenty façade materials commonly used in Shiraz, Iran. The study combined five days of field measurements with an ENVI-met simulation of an existing urban neighbourhood. Surface temperature and near-façade air temperature were measured using a surface thermometer and a temperature-humidity data logger. The field data were used to validate the simulation, which assessed pedestrian thermal comfort using Physiologically Equivalent Temperature (PET).

2. Brick-Red

The living wall achieved the lowest surface temperature, adjacent air temperature, and PET, reducing the surrounding air temperature by up to 2°C. Conversely, some high-albedo materials remained relatively cool but increased radiant exposure and PET by reflecting solar radiation into the street. Cream brick, a commonly used façade material in Shiraz, recorded among the highest surface-temperature and PET values.

10. Travertine -Gray

3. Cement-White 4. Travertine -White 5. Travertine -Cream 6. Travertine -Brown 7.Granite - Black 8. Granite - Gray 9. Ceramic - Brown 11. Porcelain - Cream 12. Porcelain - Gray 13. Artificial Stone Beige 14. Ceramic - Cream 15. Marble - Cream 16. Marble - White 17. Aluminium composite - Gray 18. Concrete - Muticolor 19. Continuous Living Wall 20. Modular living Wall

Figure 2.2.3 a)standard deviation error bars of materials’ surface temperatures during the measurement period from June 21st to June 25th from 8:00 a.m. to 8:45 p.m., c 1&2) air temperature changes in front of materials from 8:00 a.m. to 8:00 p.m., June 25th, 2022, 1 Soha S. Tabatabaei and Rima Fayaz, “The Effect of Facade Materials and Coatings on Urban Heat Island Mitigation and Outdoor Thermal Comfort in Hot Semi-Arid Climate,” Building and Environment 243 (2023): 110701, https://doi.org/10.1016/j.buildenv.2023.110701.Zones,” 1879–80.

14

b) staAndard deviation error bars of air temperatures in front of materials during the measurement period from June 21st to June 25th from 8:00 a.m. to 8:45 p.m.

ALGORITHMIC COOLING


(a)

(b)

Inference and Relevance to the Present Thesis: The study demonstrates that the thermal properties of vertical façade materials directly influence surface temperature, nearby air temperature, and pedestrian thermal comfort. It also shows that a lower surface temperature does not necessarily indicate better outdoor comfort, particularly when highly reflective materials increase the radiant load within the street. These findings support the present research by establishing façades as active components of the urban thermal environment. The study also provides a relevant methodological precedent for combining field measurements and simulation to assess façade materials within street canyons and validate the material data used in the Urban Surface Catalogue.

02 D O M A I N

15


2.3 The horizontal Bias of Remote Sensing

2.3.1 Beyond the planimetric plane Contemporary empirical research into the urban heat island (UHI) phenomenon is largely based on remote sensing methodologies, which have become the dominant lens through which we quantify the thermal behaviour of cities. Using advanced orbital sensors, such as ECOSTRESS, Landsat 8, and MODIS, researchers map land surface temperature (LST) at spatial resolutions ranging from 70 m to 100 m (often resampled to 30 m) for high-resolution missions, to one kilometre for regional sensors. These instruments operate by measuring the longwave thermal infrared radiation that the Earth’s surface emits back into space, generating valuable, decades-long, and globally available databases on the macroclimatic fluctuations of metropolises.1 However, this technological paradigm suffers from an inherent disciplinary limitation: it operates exclusively in the domain of two-dimensional, orthophoto cartography. By treating the urban landscape as a homogeneous set of pixels within a flat grid, remote sensing abstracts the city into a top-down planimetric entity. This establishes a profound gap between satellite readings and actual 3D urban microclimates. Satellite LST, therefore, measure the temperature of surfaces that are exposed and visible to the sky, leaving the pedestrian level analytically unattainable.2 While satellite macro-data are valuable for identifying regional anomalies, they must be supplemented to provide a realistic representation of the city. The underlying drivers of the Urban Heat Island (UHI) effect cannot be decoded within homogeneous pixels; instead, they operate at the micro-resolution of the street canyon.3 It is precisely within this three-dimensional space, bounded by vertical facades and their specific material compositions, that the localized radiation exchange occurs, dictating the local thermal reality.

1 James A. Voogt and Timothy R. Oke, “Thermal Remote Sensing of Urban Climates,” Remote Sensing of Environment 86, no. 3 (2003): 370–375. 2 Ibid., 378–380. 3 Timothy R. Oke, “Street Canyon Microclimate,” Atmospheric Environment 22, no. 11 (1988): 2421–2423.

16

ALGORITHMIC COOLING


1

2

3

4

5

6

Fig. 2.3.1 Examples of conventional top-down remote sensing outputs: (1) Land Surface Temperature (LST); (2) Normalized Difference Vegetation Index (NDVI); (3) Synthetic Aperture Radar (SAR); (4) Macro-Scale Weather Visualization; (5) False-Colour Satellite Composite; (6) True-Colour Satellite Imagery (Sentinel-2)

02 D O M A I N

17


2.3.2 Observational Bias and the Hybrid City This spatial limitation exposes what critical spatial theory terms an “observational bias”—a structural projection that historically privileges the horizontal plane as the primary canvas of urban organization.1 Rather than a mere technical limitation, the reliance on planimetric, nadir-projected datasets enforces a radical selectivity that occludes vertical façades, the primary geometric and thermodynamic boundaries of street canyons. In The Atlas of the Senseable City (2023), Carlo Ratti and Antoine Picon warn that traditional cartography inherently “flattens” urban metabolism, reducing three-dimensional energetic exchanges to two-dimensional geometric abstractions.2 This flattening not only erases the physical depth of the street canyon but also divorces localized microclimatic phenomena from the architectural facades that generate them. To bridge this gap, Ratti advocates for a radical break with macro-cartography, which historically views the city exclusively as a static, distant artefact. Instead, mapping the microclimatic reality of the contemporary metropolis requires highly granular, bottom-up digital taxonomies capable of capturing micro-ecological phenomena at the immediate scale of the street canyon. Within this “hybrid space”, where digital data layers inextricably merge with physical architecture, spatial data ceases to be a passive record and evolves into a new kind of building material.3

Fig. 2.3.2 Bottom-up microclimatic mapping via the MIT Senseable City Lab’s City Scanner framework. (Adapted from Ratti et al.).

1 Hu, L., & Uejio, C. K. (2024). Ground Urban Heat Island: Strengthening the Connection Between Spaceborne Thermal Observations and Urban Heat Risk Management. GeoHealth, 8(7), e2024GH001114. 2 Carlo Ratti and Antoine Picon, The Atlas of the Senseable City (New Haven: Yale University Press, 2023), 24–28. 3 Ibid., 41–45.

18

ALGORITHMIC COOLING


02 D O M A I N

19


2.3.3 Thermodynamic Street-Front Envelope While the physical properties of building materials, such as albedo, thermal mass, and emissivity, directly govern how heat is absorbed and emitted (as detailed in Section 2.1.5), existing urban climate models lack the spatial frameworks to map these properties accurately at a metropolitan scale1. Traditional simulation tools typically rely on highly simplified, uniform material assumptions across entire urban districts, ignoring the immense, hyper-local material variety found within actual street canyons2. The core challenge is therefore not defining material physics, but constructing a high-resolution spatial database that registers where these materials are actually distributed in the physical city. By mapping this precise spatial distribution of materials, this thesis introduces a fundamental shift in how we represent the built environment: the continuous thermodynamic street-front envelope. This model restores the vertical dimension to urban mapping, providing the structural depth necessary to predict the real-world thermodynamic processes driven by the materialization of the street canyon. Rather than treating the canyon as a sequence of isolated, flat property lines, this approach conceptualizes the street-front as a continuous, active thermodynamic surface that is completely decoupled from commercial property boundaries, arbitrary tax plots, or individual building functions3. Shifting the analytical focus from real-estate to continuous material and energy flows transforms computational mapping from a passive cartographic record into an active, ecological design tool.

1 Voogt, J. A., and Oke, T. R. (2003). “Thermal Remote Sensing of Urban Climates.” Remote Sensing of Environment, 86(3) 2 Stewart, I. D., and Oke, T. R. (2012). “Local Climate Zones for Urban Temperature Studies.” Bulletin of the American Meteorological Society, 93(12) 3 Ratti, C., Baker, N., and Steemers, K. (2005). “Energy Consumption and Urban Texture.” Energy and Buildings, 37(7)

20

ALGORITHMIC COOLING


-

+

Fig. 2.3.3 The continuous thermodynamic street-front envelope: transitioning from fragmented property boundaries to a unified material skin (Source: Author).

02 D O M A I N

21


2.3.4 AI, Big Data, and the Expanded Architectural Vision Building this continuous thermodynamic database at a metropolitan scale is impossible through manual mapping; it requires automated computational workflows. In Neural Architecture, Matias del Campo argues that neural networks do not simply automate drafting; they fundamentally expand architectural vision by identifying latent spatial correlations within massive, unstructured datasets that remain invisible to human analysis.1 Through this computational lens, the city is read as a dynamic, data-intensive system driven by microclimatic flows. In this context, this thesis operates within an evolving lineage of computer vision models optimized for urban microclimatology. Initial breakthroughs, such as the framework by Tarkhan et al., pioneered decoupled zero-shot workflows, combining contrastive language-image models (CLIP) with the Segment Anything Model to extract facade materials across diverse contexts without training data.2 This paradigm was subsequently advanced by the HeatMat framework (Reinbigler et al.), which consolidated automated material extraction via VisionLanguage Models (VLMs) with a 2.5D predictive engine to generate accelerated thermal simulations.3 In this pipeline, computer vision acts as the high-throughput engine for raw data harvesting. The predictive model then processes this raw data to construct a dynamic, 3D thermodynamic representation of the city. This allows architects to intervene proactively during the earliest conceptual stages of design, integrating thermal performance directly into generative workflows.

Fig. 2.3.4 Technical pipeline of the HeatMat simulation framework. VLM-driven facade material extraction and 2.5D data integration for Monte Carlo thermal simulation (Adapted from Reinbigler et al., 2026).

1 Matias del Campo, Neural Architecture: Design and Artificial Intelligence (London: Oro Editions, 2022), 45–52. 2 Nada Tarkhan, Mikita Klimenka, Kelly Fang, Fabio Duarte, Carlo Ratti, and Christoph Reinhart, “Mapping facade materials utilizing zero-shot segmentation for applications in urban microclimate research,” Scientific Reports (iz tvog Zotera dodaj godinu i broj, npr. 2024). 3 Reinbigler, L., et al., “HeatMat: Simulation of City Material Impact on Urban Heat Island Effect,” (podaci iz tvog Zotera, 2025/2026).

22

ALGORITHMIC COOLING


Case Study: HeatMat (Reinbigler et al., 2026) HeatMat is an analytical, web-compatible simulation framework designed to assess urban heat island (UHI) impacts at high spatial resolutions. To automate mapping at a metropolitan scale, HeatMat pairs pre-trained Vision-Language Models (VLMs) with open-source GIS databases. The model processes street-level imagery (Mapillary) to extract the exact percentage distribution of facade materials. This automated vertical classification supplements planimetric OpenStreetMap (OSM) footprints. Instead of employing computationally heavy 3D finite-element meshes, the system encodes building heights and extracted facade materials into 2D raster maps, generating a 2.5D representation of the urban canopy. A path-sampling Monte Carlo solver calculates coupled radiative, conductive, and convective heat transfers directly from these 2.5D maps. Reflection of the Case Study Although HeatMat proves that integrating vertical facade data into 2.5D simulations yields highly accurate thermal profiles with massive computational speedups, its utility remains strictly diagnostic. The framework is built to analyze existing urban fabrics post-facto rather than to inform active intervention.

02 D O M A I N

23


2.4 Urban-Scale Thermal Analysis

2.4.1 A Tool for Urban-Scale Vertical Material Thermal Analysis Mapping the relationship between urban materials and thermal behavior is the fundamental step to understanding the impact of surfaces, thereby changing urban material strategies to alleviate the UHI effect. With satellite technology and geospatial data, horizontal urban materials have been widely studied, resulting in many tools to optimize urban horizontal surfaces. However, while vertical surfaces are also main contributors to the UHI effect in urban canyons, there is neither sufficient vertical surface data nor available tools to analyze their thermal impact. Therefore, besides addressing the data gap, establishing an urban-scale analysis tool for vertical materials is critical for improving microclimates in cities.

Fig. 2.4.1 Eddy 3D: Urban wind flow and microclimate analysis.

2.4.2 Existing Urban Environmental Analysis Tool In urban planning and environmental modeling, most existing tools focus predominantly on horizontal simulations, primarily driven by the ready availability of geospatial datasets and a conventional emphasis on pedestrian-level comfort. Existing platforms, ranging from Eddy3D and Autodesk Forma to Infrared City, are engineered primarily to evaluate neighborhood-scale aerodynamic performance, solar exposure, and outdoor thermal indices. Consequently, building masses in these simulations serve merely as passive obstruction geometries that block direct sunlight, completely neglecting the distinct thermodynamic capacities of vertical facade materials to absorb, reflect, and store heat. Fig. 2.4.2 Autodesk Forma: Urban environmental and outdoor comfort analysis.

2.4.3 Existing Building Thermal Analysis Tool At the architectural design scale, most existing tools focus on solar radiation and shadow analysis, such as ClimateStudio and Ladybug. On the other hand, mainstream building energy analysis tools such as ENVI-met and Honeybee are primarily designed for detailed design phases. These tools require rigorous 3D modeling and comprehensive material parameters, resulting in computationally expensive runtimes. Although emerging tools like Cyclops are capable of analyzing urban-scale thermal dynamics with extraordinary speed, without the matching vertical data, mapping vertical surface thermal impacts still remains impossible. Fig. 2.4.3 Infrared City: Urban heat stress and outdoor comfort simulation.

24

ALGORITHMIC COOLING


2.4.4 Early-Phase Decision-Making Gap Early-phase decisions dictate over 40% of a building’s energy-saving capacity1, yet mainstream simulation tools operate as deterministic physical engines requiring precise material parameters. By the time projects are sufficiently defined to yield accurate results, fundamental changes are no longer feasible. This paradigm leaves designers with insufficient analytical feedback during the crucial early phases, and inability to implement effective and low-cost changes during the later stages.

Fig. 2.4.4 Climate Studio: Facade environmental analysis.

In urban-scale thermal analysis, precision is no longer the sole priority; instead, having robust comparative datasets across extensive areas is essential. Rapid execution and macro-scale investigation are increasingly necessary for modern tools to provide effective and impactful decision-making support in early planning and design.

1 Tian Han et al., “Simulation-Based Decision Support Tools in the Early Design Stages of a Green Building—A Review,” Sustainability 10, no. 10 (2018): 3696, https://doi.org/10.3390/su10103696.

Fig. 2.4.5 Ladybug: Solar radiation and sun path analysis.

Fig. 2.4.6 Honeybee: Energy balance and building material thermal analysis.

02 D O M A I N

Fig. 2.4.7 Multi-metric urban environmental analysis and visualization generated using Cyclops.

25


2.4.5 Case Study: CarbonSpace by MVRDV NEXT CarbonSpace is a free, web-based embodied-carbon assessment tool with an open API, developed by MVRDV’s research and development team MVRDV NEXT in collaboration with Studio AvW.1 The major goal of the tool is to let architects make carbon-aware decisions from the very first sketch, without having to wait until details become available. Early-Phase Decision Supporting Tool MVRDV argues that most carbon-assessment tools depend on detailed data that’s only available in later design stages. However, by the time these numbers can be produced, the geometry, structure, and material choices behind them have usually already been fixed.2 CarbonSpace responds by reversing this pattern: the system requires only minimal information, such as an estimated floor area, a rough façade area, and an assumed foundation volume, and returns an approximate carbon figure straight away. This rough estimation at an early stage allows designers to gain meaningful insight before the decision becomes too late to make. Meaningful Abstraction from Complex Database Besides the web tool, dashboard, and database that CarbonSpace provides publicly, MVRDV NEXT also condenses its underlying research into a set of design guidelines.3 From “Do not build new” as the first and most important guideline to “Reducing Weight,” the guidelines not only offer design suggestions but also point to building weight as a strong indicator of carbon impact, in which a lighter building results in less carbon emissions.4

Fig. 2.4.8 Carbon Guidelines developed by MVRDV NEXT.

1 MVRDV, “MVRDV Releases CarbonSpace for Free Public Use: A Transparent Tool to Help Reduce Embodied Carbon from Day One of the Design Process,” MVRDV, October 6, 2025, https://www.mvrdv.com/ news/4767/mvrdv-releases-carbonspace-for-free-public-use-a-transparent-tool-to-help-reduce-embodiedcarbon-from-day-one-of-the-design-process. 2 MVRDV, “MVRDV Releases CarbonSpace.” 3 MVRDV NEXT, MVRDV Carbon Guidelines (Rotterdam: MVRDV, 2026), PDF, https://www.mvrdv.com/ media/uploads/260521%20MVRDV%20NEXT%20Climate%20Carbon%20Guidelines%20A2.pdf. 4 Sanne van der Burgh, EmTech Master Class lecture (Architectural Association, London, March 19, 2026).

26

ALGORITHMIC COOLING


Fig. 1.2 CarbonSpace dashboard developed by MVRDV NEXT.

From Pipeline to Early Decision Suporting Tool Although CarbonSpace functions primarily as a tool for assessing embodied carbon, it successfully demonstrates the pipeline for scaling internal research into a publicly accessible platform. This approach allows future projects to engage with carbon assessment from the earliest conceptual stages. Furthermore, utilizing building weight as a key indication for embodied carbon provides designers with a novel, intuitive, and highly actionable metric to guide their sustainable design decisions.

02 D O M A I N

27


2.4.6 Case Study: Infrared.City

AI-Powered Hybrid Model for Early-Phase Simulation Conventional environmental simulations relying on Computational Fluid Dynamics (CFD) are heavily burdened by massive computational demands, prohibitive time costs, and steep technical barriers.² To overcome this bottleneck, Infrared.City utilizes a highly optimized “Hybrid Engine” that precisely integrates physics-based calculations with AI surrogate models.1 By assigning only the most computationally intensive wind simulations to the AI, the system achieves prediction speeds 100 times faster than traditional CFD while maintaining over 90% accuracy.2 System Framework Infrared.City employs a Software-as-a-Service (SaaS) model with open integration capabilities. The platform provides a standalone web application while utilizing API to integrate directly into familiar design environments, such as Grasshopper, Revit, GIS, and Speckle, while seamlessly pairing with Multi-Objective Optimization Algorithms (MOOA) like Wallacei or Galapagos.3 This cloud-based architecture bypasses local hardware limitations by executing intensive computational analysis on remote servers. Additionally, the AI-powered dashboard enables users to rapidly compare design iterations and Key Performance Indicators (KPIs).4 A Hybrid Model for Rapid Anlaysis

Fig. 2.4.9 The training and validation process of the AI surrogate model by Infrared.City.

While Infrared.City produces only 2D result and lack the ability to simulate surface temperature, it demonstrates the efficiency of bypassing computationally intensive CFD simulations with a hybrid surrogate model, achieving significant speed improvements while maintaining precision. It also demonstrates a successful cloud-based framework, bridging OSM geometry acquisition, web-based analytics, and cloudhosted simulation into a single portal, while seamlessly connecting to everyday design software. This allows user to rapidly acquire data and visualize result in the portal without breaking the design workflow.

Fig. 2.4.10 The solar analytic dashboard designed by Infrared.City.

1 Infrared City, “Simulation Engine Basics,” Knowledge Base, accessed July 14, 2026, https://infrared.city/ knowledge-base/simulation-engine-basics/. 2 Infrared City, “Infrared - AI-Powered Environmental Simulations,” Frequently Asked Questions. 3 Infrared City, “Rhinoceros/GH” Integration, accessed July 14, 2026, https://infrared.city/integration/. 4 Infrared City, “Infrared - AI-Powered Environmental Simulations,” Frequently Asked Questions, accessed July 14, 2026, https://infrared.city/.

28

ALGORITHMIC COOLING


Fig. 2.4.11 The Thermal Comfort Simulation in the web portal developed by Infrared.City.

02 D O M A I N

From Research Pipeline to Early-Phase Design Tool The analysis of case studies highlights how emerging tools can effectively bridge early-phase information gaps, providing critical environmental insights during the most pivotal design moments. This research aims to bridge the gap by developing a urban analysis tool to transform raw urban data into actionable decision support information.

29


2.4.7 3D Data Visualisation To take thermal analysis into another level, data visulaisation needs to be implemented as a method for users interpret data more easily. Interactive visualisation is a powerful and efficient way to explore and communicate scientific data, especially when urban simulation generates lots of data. Stockhom-19 In this project, 3D contour in different colours were implemented to sample data and create eye catching 3D data, allowing user to quickly distinguish the usage of various urban services and amenities in Stockholm.1 The height and color difference allows rapid identification of higher usage between different period. Urban Climate InteracTable In this project, different 3D data visualisation method was implemented using VR development.2 By changing different mode, user can interpret originally complex data with more efficiency and clarity. This project turns complex urban heat analysis into easy-interpret and interactive 3D visualisation, providing extra information on top of the base analysis.

Fig. 2.4.12 Different 3D data visualisation method was implemented in InteracTable to present Urban Heat Island effect and Ground temperatures.

1 Ann Legeby et al., “New Urban Habits in Stockholm Following COVID-19,” Urban Studies 60, no. 8 (2023): 1448, https://doi.org/10.1177/00420980211070677. 2 Nico Reski et al., “Urban Climate InteracTable: Towards an Immersive Contextual Data Analysis Platform to Visualize and Explore Urban Heat,” Virtual Reality 30, no. 1 (2026): 7, https://doi.org/10.1007/s10055025-01264-4.

30

ALGORITHMIC COOLING


Fig. 2.4.13 Coloured 3D contours was utilised to present urban data from project Stockholm-19.

02 D O M A I N

31


2.5 Design Problem Synthesis Existing Urban Heat Island (UHI) research has substantially advanced the understanding of urban thermal behaviour. However, these approaches remain constrained by two fundamental limitations: the inability of satellite observations to map vertical surfaces, and the reliance of detailed simulation tools on fully specified geometries. Consequently, the thermal impact of vertical envelopes remains unmapped, leaving planners without an accessible framework to evaluate material decisions during early design stages. This thesis responds to these limitations by proposing an automated data acquisition and AI-assisted post-processing pipeline to map cityscale facade materials. Coupled with a surrogate temperature prediction model, these modules serve as the core data input and rapid inference engine for urban thermal simulation. To scale this workflow into an accessible decision-support system, a web portal is developed to bridge raw data with thermal analysis, providing insights that were previously unavailable to planners and designers. Rather than replacing existing benchmarked environmental simulation applications, the framework focuses on a lightweight prediction system capable of informing material selection at the earliest stages of design. By bridging the gap between urban climate science and architectural decision-making, this research aims to establish a scalable methodology for integrating thermal performance into climate-responsive urban planning. 32

ALGORITHMIC COOLING


2.6 Research Question How do urban vertical surface materials collectively contribute to UHI intensity in London, and can this relationship be estimated and visualized by rapidly acquire urban facade data and predict thermal behavior by a trained surrogate model? Can we answer “How hot is London”, and “How to Cool it down” by creating an analytic tool that maps thermal impact of urban facade material?

02 D O M A I N

33


03 Method To address current limitations in conducting urban-scale investigations of facade thermal behavior, deploying emerging computational technologies to automate and optimize the analytical workflow is essential. By integrating machine learning (ML), automated data acquisition pipelines, and vision-language models (VLMs), this methodological framework significantly accelerates and automates data collection, semantic parsing, and post-processing. This computational workflow replaces human-intensive manual

Fig. 3.1.1 Facade images visualization.

tasks with scalable surrogate and computer vision models,

The spatial distribution of processed facade images.

thereby enabling comprehensive, city-scale microclimatic and environmental analysis.


35


3.1 Overall Framework

To achieve the ultimate goal of mapping the relationship between vertical surface materials and their thermal behaviour across London, this research adopts a five-phase methodology (Fig 3.1.2). The workflow progresses from localized digital thermodynamic studies to a city-scale machine learning prediction model, culminating in an interactive web portal for material data acquisition and real-time visualization. Benchmarking and Prototyping The project begins with a series of digital studies investigating how specific building materials affect heat retention and emission. Honeybee - utilizing the robust EnergyPlus simulation engine - serves as the primary benchmarking tool to generate baseline scenarios. Concurrently, a prototype data acquisition and post-processing pipeline is constructed to calibrate and validate these simulation outputs, ensuring baseline accuracy. Data Automation and Surrogate Modelling To scale up the investigation, an API service is implemented to connect the automated workflows with a relational database, facilitating the efficient storage, querying, and processing of urban data. Because traditional Honeybee simulations are computationally prohibitive for city-scale applications, an Machine Learning (ML) surrogate model is trained using the benchmarked data. This approach bypasses computational bottlenecks while maintaining predictive precision. Prior to scaling, both the data pipelines and the surrogate model are iteratively calibrated and validated to ensure baseline accuracy. Real-Time Visualization Portal Finally, the research culminates in the development of a user-facing web portal. This interface hosts OpenStreetMap (OSM) base tiles, dynamically queries building geometry and facade imagery from the object storage and executes the trained ML model in real-time. This seamless integration allows users to rapidly visualize and interact with the impacts of facade materials on London’s Canyon Urban Heat Island (CUHI) effect.

Fig. 3.1.2 System Logic Diagram illustrates the process from research development, prototyping, scaling up pipelines, to the portal that predict surface temperature for urban surface material.

36

ALGORITHMIC COOLING


Research Interest Research Development

Urban Heat Island (UHI) Effect

Research Question Urban Vertical Surface vs. Thermal Behavior

Data Acquisition Pipeline

Prototype Simulation How Heat Transfer

Scrapper & Parameter Calibration API Source Adjustment

Post-Process Pipeline

ST Prediction Iterative Calibration

Iterative Optimization Process

Scale Up

Snapping, Rotating, Distorting, Aligning, Cropping, Recognising

Training Dataset Prepare Surrogate Model Training

Model Validation

Model Validation

Accuracy Calibration Benchmark Model Validation

Accuracy Calibration Human Process Validation

Iterative Calibration

Prototype

Surface Temperature (ST)

Scale Up

APP Design

Pipeline, Engine, Server, Storage

POST

03 M E T H O D

Data Harvesting Scrapping through API Post-Process

ST Model Predicting Trained Model .onnx

Database SQL Relational Database R2 Object Storage

GET POST

Data Post-Processing Scrapping through API Post-Process

Backend Task Deployment api.py

Portal (Frontend) <Unity vs Web> Decision Pending

Primary Researchh & Design Process Iterative Optimiaztion Process

37


3.2 Thermal Simulation

The research methodology connects the investigation of façade thermal behaviour with the development of a computational tool for urban-scale assessment. It progresses through three stages: identifying the processes that influence canyon thermal conditions, generating a structured simulation dataset, and training a surrogate model for rapid prediction. Each stage informs the next, translating experimental observations into a framework for evaluating material interventions. 3.2.1 Experiments Controlled digital experiments compare façade materials and colour alternatives under consistent canyon geometry and weather conditions. The analysis examines how solar reflectance, absorptance, emissivity and thermal storage properties influence surface temperature, shortwave and longwave exchange, outgoing radiation and mean radiant temperature (MRT). Orientation, shading and solar exposure provide the environmental context for interpreting these responses. This stage establishes which quantities are necessary to assess material performance and its implications for pedestrian radiant exposure. 3.2.2 Simulation and Data Generation The experimental findings guide the selection of input variables and parameter ranges for a parametric workflow in Grasshopper. Each scenario combines urban geometry, material properties, façade-grid locations and environmental inputs. Honeybee, using OpenStudio and EnergyPlus, calculates façade surface temperatures, while Anemone automates successive simulations across the selected combinations. A C# workflow organises the resulting records, linking each case, time step and grid location to its inputs and corresponding temperature, producing the dataset required for model training. 3.2.3 Machine Learning and Validation The dataset is used to train a Regression model within LunchboxML, which learns the relationship between the input parameters and façade surface temperature. Predictions are evaluated against held-out simulation results to assess accuracy and inform refinement. The validated model can then estimate temperatures for new scenarios within its training domain, reducing reliance on repeated thermal simulations. These estimates can support subsequent physics-based calculations of radiative exchange and MRT, enabling faster assessment of urban material strategies.

Fig. 3.2.1 System Logic Diagram illustrates the process fromperforming experiments to translating heavy simulation into fast prediction method forcity scale model

38

ALGORITHMIC COOLING


03 M E T H O D

39


3.3 Data Acquisition & Post Process Pipeline

Introduction to Street-Level Urban Capture While Mobile LiDAR Systems are a prime example for mapping vertical data, they are expensive, closed-source, rarely updated, and simply not scalable on a global scale. To address these limitations, this methodology relies instead on street-level images that effectively capture the city within the urban canyon.

Fig. 3.3.1 Mobile LiDAR point cloud scan (Carlo Ratti Senseable City Lab).

Fig. 3.3.2 Sequential stacking of raw streetlevel imagery.

40

ALGORITHMIC COOLING


3.3.1 Geospatial Data Harvesting & Urban Filtering

2 OSM building filter

The acquisition pipeline is built upon a custom Python environment that integrates Google Street View (GSV) as the primary image source and OpenStreetMap (OSM) for foundational urban geometry. To optimize computational resources, the spatial scraping is strictly controlled: virtual nodes are generated every 10 meters along the street network axes. The system then applies a spatial proximity filter—if an OSM building footprint is detected within a 30-meter radius of a node, the system triggers the nearest GSV camera to extract the panorama and its corresponding metadata using the Google Maps Tile API.

Fig. 3.3.3 Urban-scale geospatial harvesting logic. Virtual nodes are generated at 10-meter intervals along street networks (left) and crossreferenced with a 30-meter building proximity filter (center) to trigger targeted metadata acquisition.

+ 03 M E T H O D

30m

41


3.3.2 Vector-Aligned Facade Extraction and Reprojection To convert spherical panoramas into distortion-free architectural elevations, the imagery is geometrically aligned with real-world spatial vectors. The module first processes OpenStreetMap (OSM) building footprints to generate linear facade segments. By analyzing these segments relative to the street network, the algorithm identifies the specific building facade most parallel to the road and calculates its exact surface normal. The 360-degree camera view is then dynamically reoriented and cropped directly along this perpendicular axis, yielding a true orthogonal projection of the street-front.

Ci

Ci

3.3.3 Computer Vision and Material Segmentation The normalized street fronts are subsequently routed into a localized AI environment (ComfyUI) for advanced semantic processing. This occurs in two critical phases. First, object detection models identify and mask out transient urban noise, such as vegetation, vehicles, and pedestrians, that obstruct the architecture. Second, the isolated, clean facades are processed through vision models that perform pixellevel material segmentation. This translates raw visual data into accurate, color-coded masks representing materials (e.g., glass, brick, concrete).

Figure 3.3.4 Image-to-vector spatial projection via viewing frustum intersection. Figure 3.3.5 Dynamic pixel weighting and multi-view fusion across spatial bins.

42

ALGORITHMIC COOLING


3.3.4 Backend Infrastructure and Data Storage Relational Database To scale the automated data-acquisition pipeline, a relational database is essential for storing and managing large volumes of data, including spatial geometries, image metadata, and associated attributes. PostgreSQL was selected as the database management system since it is open-sourced and backed by an extensive ecosystem.1 PostGIS, a spatial extension for PostgreSQL, enables the database to store and query spatial coordinates and geometries, including points, lines, and polygons2 which can be readily accessed and visualised through GIS platforms such as QGIS.34 Object Storage Cloudflare R2 stores the panoramic and post-processed image data, with each image linked to its metadata in PostgreSQL via a dedicated URL reference.5 This separates object storage from the relational database, avoiding the performance overhead of storing large binary files directly in SQL. Cloud Server An Oracle Cloud Infrastructure (OCI) virtual machine hosts the PostgreSQL instance as an always-on server, allowing the database to be queried, updated, and modified by any team member, from any device, at any time.6 The same server also hosts the web portal, providing secure and managed public access. Backtend Deployment 3.3.6 PostgreSQL database queried using PGAdmin application. 3.3.7 PostGIS geometry data and metadata visualized in QGIS application.

Flask API, a lightweight Python web framework, is implemented to receive HTTPs requests from the browser and data post-process pippeline.7 It executes the corresponding SQL query, and returns the result as JSON.

1 The PostgreSQL Global Development Group, PostgreSQL 16.0 Documentation, PostgreSQL Global Development Group, 2024, https://www.postgresql.org/docs/. 2 PostGIS Development Group, PostGIS: Spatial and Geographic Objects for PostgreSQL, version 3.4, PostGIS, 2024, https://postgis.net/. 3 QGIS Development Team, QGIS Geographic Information System, Open Source Geospatial Foundation, 2024, https://www.qgis.org/. 4 pgAdmin Development Team, pgAdmin 4: Open Source Management Tool for PostgreSQL, PostgreSQL Global Development Group, 2024, https://www.pgadmin.org/. 5 Cloudflare, Inc., “Cloudflare R2: S3-Compatible Object Storage,” Cloudflare Documentation, accessed July 15, 2026, https://www.cloudflare.com/developer-platform/r2/. 6 Oracle Corporation, “Compute Virtual Machines,” Oracle Cloud Infrastructure Documentation, accessed July 15, 2026, https://docs.oracle.com/en-us/iaas/Content/Compute/Concepts/computeoverview.htm. 7 Pallets Projects, Flask Documentation (3.0.x), Pallets Projects, 2024, https://flask.palletsprojects.com/.

03 M E T H O D

43


3.4 Analytic Portal

3.4.1 Frontend Platform The frontend web application is built using vanilla JavaScript, integrating open-source libraries such as MapLibre and OpenStreetMap for spatial context, alongside Three.js for interactive visualization, such as rendering vertical surfaces, heat particles, and heat terrain. Apache ECharts was implemented for interactive analytical graphs. MapLibre GL JS MapLibre GL JS is an open-source, WebGL-based vector map library, serving as portal’s base map.1 It renders vector tiles derived from OpenStreetMap, extrudes buildings through fill-extrusion, and handles pan, zoom and tilt. Project data, such as panorama coverage, is served to it as vector tiles from PostGIS. OpenStreetMap OpenStreetMap is an open, crowd-sourced geographic database that supplies the building footprints and height tags.2 Buildings without a measured height are estimated from their storey count. The extruded buildings serve as occluders in the sky view factor calculation and as the massing context in Analytic Mode. Apache Echarts Apache ECharts is an open-source charting library, used for the interactive 2D charts in Analytic Mode: a line graph, a day–night radar chart and a material composition bar chart.3 The charts read the same data as the 3D view, ensuring consistent graphic display.

1 MapLibre Contributors, MapLibre GL JS, version 5.24.0, software library, MapLibre, 2026, https://maplibre. org/. 2 OpenStreetMap Contributors, “Planet Dump,” OpenStreetMap Foundation, accessed July 15, 2026, https://www.openstreetmap.org/. 3 Apache Software Foundation, Apache ECharts, version 5.x, software library, Apache Software Foundation, 2024, https://echarts.apache.org/.

Fig. 3.4.1 Frontend Portal maps the thermal impact from urban facade data. Fig. 3.4.2 MapLibre GL JS serves as the base map layer. Fig. 3.4.3 OpenStreetMap serves as the geometry layer. Fig. 3.4.4 Apache Echarts draws interactive 2D analytical graphs.

44

ALGORITHMIC COOLING


Three.js Three.js (r169, WebGL 2) is implemented to render complex 3D microclimatic layers beyond the scope of MapLibre GL JS.1 It operates as an integrated MapLibre custom layer sharing the primary WebGL context in portal mode, while it also serve as an independent analytical renderer with a dedicated canvas loop in analytic mode. a. Vertical Surface Layer: It renders facade images, material masks, and all the per-cell thermal results (heatmaps). b. Heat Particle Layer: A particle system rendering up to 220,000 particles in a single draw call is implemented to visualize radiant load efficiently. c. 3D Data Visualisation: Three.js renders sampled data field into 2D heat zones, 3D contour lines, and an extruded 3D heat terrain, where each rendered polygon is also implemented as the interactive boundary used for regional selection. Claude Code Claude Code, an AI coding agent, was deployed inside Visual Studio Code to implement the portal’s frontend.2 Claude Sonnet 5 was used for standard coding tasks, while Claude Opus 5 was used for complex tasks, context engineering, and debugging. The agent’s workflow was constrained through persistent context engineering, utilizing structured briefs for every development session alongside strict Definition of Done constraints. Worklog.md and Architecture.md were implemented to synchronize development state between the designer and the agents. Finally, architectural diagrams were used to control module modifications through the Model Context Protocol (MCP),3 and automated regression tests were executed before every commit to ensure system reliability.

Fig. 3.4.5 The facade image layers rendered by Three.js.

1 Ricardo Cabello and Three.js Authors, Three.js, version r169, software library, GitHub repository, 2024, https://github.com/mrdoob/three.js. 2 Anthropic, Claude Code, software agent, Anthropic, 2026, https://www.anthropic.com/claude-code. 3 Anthropic, Model Context Protocol (MCP), open specification, Anthropic, 2024, https://modelcontextprotool.io/.

Fig. 3.4.6 The heat particles rendered by Three.js. Fig. 3.4.7 The heat terrain and contours rendered by Three.js. Fig. 3.4.8 Claude Code was untilised in VsCode to integrate the frontend portal.

03 M E T H O D

45


04 Research Developement This chapter presents the development of the research from proofof-concept experiments to the formulation of a scalable assessment framework for urban heat analysis. It begins by investigating the influence of vertical surface materials on the urban microclimate through both field studies and digital experiments, establishing the relationship between material properties, surface temperature, and pedestrian thermal conditions. Building on these findings, a comprehensive Material Catalogue is developed to compile the thermo-physical and radiative properties of common urban construction materials relevant to the London context. The chapter then introduces the Automation Pipeline, which integrates material data with urban geometry and environmental parameters to enable rapid, early-stage evaluation of urban heat performance. Together, these stages transform isolated experimental observations into a structured, data-driven workflow that supports informed material selection and evidence-based design decisions for mitigating the Urban Heat Island effect.

Fig. 4.1.1 3D semantic mask projection. Visualization of material classification masks mapped onto the urban geometry. The spatial distribution accounts for the redundant overlapping of multiple real-world image captures.


47


4.1 Field Study

4.1.1 Surface Temperature Variation among Horizontal & vertical surfaces in a Canyon A field study on 9th May 2026 at 11:30 a.m. used a thermal camera to examine surfaces at Russell Square, London, while the outdoor air temperature was approximately 14 degrees Celsius. Phone photographs documented the visible surfaces, and thermal images recorded their apparent surface temperatures. The observations revealed substantial thermal heterogeneity within the site, with surface-temperature differences of up to 22 °C across façades and 18 °C across horizontal surfaces. This indicates that surface temperature is governed not only by ambient air temperature, but also by the interaction of orientation, solar exposure, shading, material colour, surface roughness and construction. The greater temperature range observed across vertical surfaces reinforces the need to examine façades as active components of urban heat distribution. Although exploratory, this survey informed the controlled material and canyon-scale experiments presented in the following sections.

Figure 4.1.2 Tool used for field study Device used: Thermal Camera Model: 102932 - TOPDON TC004

48

ALGORITHMIC COOLING


Figure 4.1.3 Thermal Scan using a handheld Thermal Camera Vs photo of different surface material (horizontal & Vertical surfaces) within a canyon. Date of Experiment: 9th May, 2026 Time of Experiment: 11:30 am Place of Experiment: Russel Square Outdoor Temperature: 14’C Device used for the Experiment: Thermal Camera

Maximum Temperature

Selected Surface Temperature

Minimum Temperature

04 R E S E A R C H D E V E L O P M E N T

49


4.2 Digital Experiments

The digital experiments were designed to isolate the influence of façade material properties within a simplified urban-canyon model. Canyon geometry, orientation, weather data and boundary conditions were held constant, enabling differences in simulated surface temperature to be attributed primarily to material response. Seven representative façade materials were evaluated: glass, wood, stone, concrete, steel, white plaster and brick. Surface-temperature profiles were simulated for north- and south-facing façades over a 24hour period.

4.2.1. Impact of Materials on Surface Temperature The results demonstrate distinct thermal responses despite identical ambient conditions. South-facing surfaces exhibited greater daytime temperature divergence due to direct solar irradiance, whereas northfacing surfaces were predominantly affected by diffuse sky radiation and inter-reflection within the canyon. Material-related differences remained apparent on north façades, although with a reduced daytime range. Across the simulated cases, steel exhibited the highest peak surface temperature, reaching approximately 62 °C, while glass recorded the lowest peak surface temperature, at approximately 33 °C.

Figure 4.2.1 Surface Temperature of different materials on South Facing facade

Figure 4.2.2 Surface Temperature of different materials on North Facing facade

50

ALGORITHMIC COOLING


Selected Material Properties Solar reflectance

Visible absorptance

Thermal capacity (J/m³·K)

0.15

0.85

0.10

21,00,000

0.90

0.60

0.40

0.70

8,16,000

Rough

0.90

0.65

0.35

0.65

26,00,000

1,000

Medium Rough

0.90

0.65

0.35

0.65

22,00,000

7,833

465

Smooth

0.28

0.70

0.30

0.70

36,42,345

0.40

1,850

840

Medium Rough

0.35

0.20

0.80

0.30

15,54,000

0.48

1,513

800

Rough

0.93

0.70

0.30

0.70

12,10,400

Thermal Solar absorptance absorptance

Material

Thickness (m)

Conductivity (W/mK)

Density (kg/m³)

Specific heat (J/kgK)

Roughness

Glass

0.0060

1.00

2,500

840

Very Smooth

0.84

Wood

0.0250

0.14

510

1,600

Medium Smooth

Stone

0.0500

2.80

2,600

1,000

Concrete

0.1500

1.65

2,200

Steel

0.0050

54.00

White Plaster

0.0200

Brick

0.1025

Figure 4.2.3 Table showing the different thermal properties of the materials

70 60

Temperature in ‘C

50

40

Glass

30

Glass 20

Wood

Air 10

Wood

0 0

2

4

6

8

10

12

14

Hour of the day

16

18

20

22

Stone

24

70

Stone Concrete

60

Temperature in ‘C

50

Concrete

40

Steel

30

Steel 20

White Plaster

Air 10

White Plaster

0 0

2

4

6

North-Facing Facade 04 R E S E A R C H D E V E L O P M E N T

8

10

12

14

Hour of the day

16

18

20

22

Brick

24

Brick

51


4.2.2. Impact of color on Surface Temperature This experiment isolated the effect of surface colour by applying different colour finishes to the same base brick material while maintaining identical geometric and environmental conditions. The results demonstrate that colour alone can substantially alter façade thermal behaviour by changing solar reflectance and absorptance. Lighter surfaces reflect a greater proportion of incident shortwave radiation and consequently experience lower solar heat gain. On the south-facing façade, the darker brick reached a peak surface temperature of approximately 53 °C, compared with 48 °C for the original brick and 42 °C for the lighter brick. Therefore, changing the surface colour produced a maximum temperature difference of approximately 11 °C under identical material, weather and canyon conditions.

Figure 4.2.4 Surface Temperature of different color of same materials on South Facing facade

Lighter color reflects more

Darker color stores more

Darker color emits more

52

Figure 4.2.5 Surface Temperature of different color of same materials on North Facing facade

ALGORITHMIC COOLING


Brick Material Properties Material

Thickness (m)

Conductivity (W/mK)

Density (kg/m³)

Specific heat (J/kgK)

Roughness

Thermal absorptance

Solar absorptance

Solar reflectance

Visible absorptance

Thermal capacity (J/m³·K)

Emissivity

Darker Brick

0.1025

0.48

1,513

800

Rough

0.93

0.85

0.15

0.85

12,10,400

0.93

Lighter Brick

0.1025

0.48

1,513

800

Rough

0.93

0.55

0.45

0.55

12,10,400

0.93

Brick

0.1025

0.48

1,513

800

Rough

0.93

0.70

0.30

0.70

12,10,400

0.93

Figure 4.2.6 Table showing the different thermal properties of the different color of the same materials

70

60

Temperature in ‘C

50

40

30

20

Air 10 0 0

2

4

6

8

10

12

14

Hour of the day

16

18

20

22

24

70

60

Temperature in ‘C

50

Darker Brick

40

30

Darker Brick

20

Air

Lighter Brick

10

Lighter Brick 0 0

2

4

6

04 R E S E A R C H D E V E L O P M E N T

8

10

12

14

Hour of the day

16

18

20

22

Brick

24

Brick

53


4.2.3 Assumption: What happens when the entire city is painted White? Because lighter-coloured façades exhibit lower surface temperatures, it is often assumed that painting urban surfaces white will cool the surrounding city. However, surface temperature alone cannot determine the thermal performance of an urban canyon. High-albedo materials absorb less solar energy but reflect a greater proportion of shortwave radiation, which may be redirected towards adjacent façades, the street surface or pedestrians in enclosed conditions. Assessment of local radiant exposure must therefore consider material thermal properties in addition to surface temperature, including solar reflectance, absorptance, emissivity and thermal storage. These properties determine whether energy is absorbed, reflected, stored or emitted back into the canyon as shortwave and longwave radiation. Consequently, the effectiveness of lighter coatings depends on canyon geometry, orientation, sky-view factor, surrounding materials and pedestrian location; a lower façade temperature may redistribute radiation rather than reduce pedestrian-level heat exposure.

Plaster

Albedo Albedo White WhitePlaster Plaster

ete

Density Density

Emissivity Emissivity

A

Brick Brick Steel Steel Concrete Concrete Glass Glass

Density

Stone Stone

Specific Heat

Thickness Thickneess

SpecHC Capacity

Thickneess Absorptance Absorptance

54

Fig. 4.2.7 Caption set small and grey in the narrow inner column, beneath its figure.

ALGORITHMIC COOLING

Abso


Solar absorptance primarily governs daytime thermal response by determining the proportion of incident shortwave radiation converted into heat at the surface. Thermal conductivity, density, specific heat capacity and material thickness subsequently regulate the transfer, storage and release of this absorbed energy within the façade assembly. Thermal emissivity governs longwave radiative exchange between the surface, the sky and surrounding canyon surfaces, influencing both daytime radiation balance and night-time cooling.

Fig. 4.2.8 Table explaining the thermal effect as a response of given thermal properties of material 04 R E S E A R C H D E V E L O P M E N T

Thermal Property

Sources

Expected thermal effect

Solar reflectance or albedo

Fraction of incoming solar radiation reflected

Higher values usually lower absorbed solar gain at the surface but increase reflected radiation

Solar absorptance

Fraction of incoming solar radiation absorbed

Higher values generally increase daytime heating and potential energy storage

Thermal emissivity

Efficiency of longwave emission and absorption

Higher values strengthen longwave exchange with the surroundings

Conductivity

Rate of heat transfer through the material

Changes the speed and depth of heat movement through the construction

Density and specific heat

Energy stored per unit volume Higher thermal capacity can for a temperature change delay heating and cooling

Thickness

Depth of the material layer

Affects total storage and conduction response

55


4.2.4 Impact of Material on Radiant Load The experiment compared the radiative behaviour of brick, steel and white-plaster canyons. The analysis considered daytime surface temperature, night-time surface temperature, daytime net radiation loss and night-time net radiation loss. Brick reflected less solar radiation during the day and absorbed a greater proportion of the incident energy. This produced greater heat storage within the material. White plaster reflected more solar radiation and absorbed less, resulting in a lower daytime surface temperature. Steel also reflected a relatively high proportion of the incoming solar radiation under the properties used in the simulation. During the day, the high-albedo surfaces produced a greater reflected radiant load within the canyon. After sunset, shortwave reflection was no longer present, and the thermal behaviour was mainly influenced by stored heat and longwave emission. Brick retained more heat and cooled more slowly than white plaster. The results show that high-albedo materials can increase the daytime radiant load through reflection, while more absorptive materials can increase the night-time radiant load through delayed heat release. Surface temperature alone is therefore insufficient for comparing the thermal effect of façade materials within an urban canyon.

Selected Material Properties Solar reflectance

Visible absorptance

Thermal capacity (J/m³·K)

0.70

0.30

0.70

36,42,345

0.35

0.20

0.80

0.30

15,54,000

0.93

0.70

0.30

0.70

12,10,400

Material

Thickness (m)

Conductivity (W/mK)

Density (kg/m³)

Specific heat (J/kgK)

Roughness

Thermal Solar absorptance absorptance

Steel

0.0050

54.00

7,833

465

Smooth

0.28

White Plaster

0.0200

0.40

1,850

840

Medium Rough

Brick

0.1025

0.48

1,513

800

Rough

Fig. 4.2.9 Table showing the different thermal properties of the different color of the same materials 56

ALGORITHMIC COOLING


Day Net Loss

Day ST

Night ST

Steel + Steel

Night Net Loss

Steel

Day Net Loss

Day ST

Night ST

White Plaster + White Plaster White Plaster

Night Net Loss Day Net Loss

Day ST

Fig. 4.2.10 Diamond chart showing comparision of Surface temperature Vs Radiant Loss during day & night

Night ST

Brick + Brick

Night Net Loss

Outgoing Radiation in w/sqm

Brick

800 600 400 200 0

0

2

4

6

8

10

12

14

16

18

20

22

24

Hour of the day Fig. 4.2.11 Graph showing Radiation loss throughout the day for Brick, steel and white plaster 04 R E S E A R C H D E V E L O P M E N T

57


4.2.5 Impact of Surrounding Materials on Heat Absorption by nearby Buildings This experiment examined how the material of a surrounding façade affected the heat absorbed by a nearby brick building. The target brick façade remained unchanged, while the opposing façade was varied between brick, steel and white plaster. In the brick-and-brick canyon, the opposing façade reflected less solar radiation toward the target wall. The brick target therefore received less reflected radiation from its surroundings. When the opposing façade was changed to steel or white plaster, a larger proportion of the incoming solar radiation was reflected across the canyon. The brick-and-white-plaster configuration produced the greatest reflected load on the target brick wall. Because brick has relatively high solar absorptance, part of this additional radiation was absorbed and stored by the target façade. The reflective surrounding surface remained cooler but increased the incident energy received by the nearby building. This experiment demonstrates that the thermal behaviour of a façade is influenced by the materials surrounding it. A material may reduce its own surface temperature while increasing heat absorption in a neighbouring building. Façade materials must therefore be evaluated as interacting elements within the urban canyon.

Material

Thickness (m)

Conductivity (W/mK)

Density (kg/m³)

Specific heat (J/kgK)

Roughness

Thermal absorptance

Solar absorptance

Solar reflectance

Visible absorptance

Thermal capacity (J/m³·K)

Brick

0.1025

0.48

1,513

800

Rough

0.93

0.70

0.30

0.70

12,10,400

Steel

0.0050

54.00

7,833

465

Smooth

0.28

0.70

0.30

0.70

36,42,345

White Plaster

0.0200

0.40

1,850

840

Medium Rough

0.35

0.20

0.80

0.30

15,54,000

Fig. 4.2.12 Table showing the different thermal properties of the different color of the same materials 58

ALGORITHMIC COOLING


Day Net Loss

Day ST

Night ST

Brick + Brick

Night Net Loss

Brick

Day Net Loss

Day ST

Night ST

Brick + Steel

Night Net Loss Day Net Loss

Day ST

Outgoing Radiation in w/sqm

Fig. 4.2.13 Diamond chart showing comparision of different material combination in a canyon in terms of Surface Temperature Vs Radiant Loss

Night ST

Brick + White Plaster

Night Net Loss

800 600 400 200 0

0

2

4

6

8

10

12

14

16

18

20

22

24

Hour of the day Fig. 4.2.14 Graph Showing the radiant loss throughout the day for 3 different material combination in a canyon 04 R E S E A R C H D E V E L O P M E N T

59


4.2.6 Conclusion The digital experiments demonstrate that façade material selection significantly alters the radiative behaviour of an urban canyon, even when geometry and meteorological conditions remain unchanged. Across the tested material combinations, changes in façade material produced variations of up to 24% in outgoing radiation during the day and 76% at night. Daytime differences were primarily associated with variations in shortwave reflection and solar absorption, whereas nighttime differences reflected the release of stored heat and longwave radiative exchange between canyon surfaces. These changes also affected the local mean radiant temperature (MRT), with a maximum variation of approximately 3 °C between the simulated cases. The results confirm that material choice should not be assessed solely through façade surface temperature: its radiative properties influence how energy is reflected, stored and emitted within the canyon, directly affecting pedestrian-level radiant exposure.

NE

NW

SE

SE

Brick _ 00 am Brick _ 03 am Brick _ 06 am Brick _ 09 am

Brick _ 12 pm

Brick _ 15 pm

Brick _ 18 pm Brick _ 21 pm

60

Figure 4.2.15 Surface temperature change on the facade of brick throughout the day at interval of 3 hours

ALGORITHMIC COOLING


Figure 4.2.16 Table showing the radiation outgoing during day and night for differrrent material combination in a canyon

Outgoing Radiation ( W/sqm ) Canyon Material Combination

Daytime

NightTime

Steel +Steel

5,362.31

64.80

White Plaster + White Plaster

4,775.79

64.87

4,027.22

269.37

4,553.36

178.42

4,841.51

215.17

Brick +Brick Brick + White Plaster Brick + Steel

Daytim

Figure 4.2.17 Diamond chart showing comparision of different material combination in a canyon in terms of Surface Temperature Vs Radiant Loss Figure 4.2.18 Diamond chart showing comparision of different material combination in a canyon in terms of MRT Vs Radiant Loss

Day Net Loss

Day Net Loss

Steel + Steel White Plaster + White Plaster Brick + Brick

Day ST

Night ST

Day MRT

Night MRT

Brick + White Plaster Brick + Steel

Outgoing Radiation in w/sqm

Night Net Loss

Night Net Loss

800 600 400 200 0

0

2

4

6

8

10

12

14

16

18

20

22

24

Figure 4.2.19 Graph showing the comparision of radiant loss for 5 different combination of materials for the canyon

04 R E S E A R C H D E V E L O P M E N T

61


4.3 Identifying and Mitigating Data Noise

While full automation enables massive metropolitan scale, it inherently trades off perfect human precision. Transitioning from controlled samples to city-wide datasets introduces distinct categories of data noise into the system. Quantifying these errors and documenting the algorithmic workarounds was the hardest and most critical phase of the system’s calibration. Rather than presenting a flawless final system, this chapter chronologically documents the data pipeline’s bottlenecks and their computational mitigations. From acquiring restricted street-level imagery and resolving severe GPS drift, to establishing geometric camera rules and benchmarking semantic AI models. This rigorous empirical calibration ensures the accuracy and structural integrity of the dataset before it reaches the final multi-depth analysis.

62

ALGORITHMIC COOLING


Fig. 4.3.1 Color-coded material masks: examples of anomalies, successful and unsuccessfull segmentations.

04 R E S E A R C H D E V E L O P M E N T

63


4.3.1 Input Data Acquisition and The Openness Dilemma The initial phase of the automated processing pipeline requires securing a spatially consistent and reliable source of street-level imagery. To this end, a comparative field test was conducted within London’s complex urban fabric, specifically covering mixed-use street corridors in the London Borough of Camden (along Tottenham Court Road) and the financial district of the City of London. During this evaluation, the open-source Mapillary platform (which relies on crowd-sourced data) was benchmarked against the standardized Google Street View (GSV) APIs. While Mapillary represents an ideal “open-data” paradigm, our empirical evaluation demonstrated that its crowd-sourced nature suffers from extreme geometric and optical variability, which compromises automated coordinate calculations: -

Extreme spatial drift in dense urban canyons.

-

Varying lenses, motion blur, windshield reflections, and inconsistent mounting heights.

-

Coverage remains fragmented even in highly mapped areas.

Conversely, GSV utilizes dedicated survey vehicles to capture standardized 360-degree equirectangular panoramas at a fixed 2.5-meter height. This panoramic baseline is crucial: it allows the pipeline to programmatically crop the sphere and mathematically define the exact Field of View (FOV) per facade, completely bypassing hardwarebased optical distortions. Consequently, GSV was selected as the primary processing engine. However, this choice introduced a data openness dilemma. GSV is a closed commercial ecosystem with strict API rate limits and high costs. Therefore, the algorithm could not blindly download imagery; it required rigorous optimization to query only the absolute minimum number of spatial nodes necessary to reconstruct the urban canyon.

Fig. 4.3.2 Mapillary spatial coverage in the City of London, exhibiting severe track fragmentation and GPS drift typical of deep urban canyons. Fig. 4.3.3 Standardized, continuous spatial coverage of Google Street View (GSV) imagery within the identical test sector.

Table 4.3.4 Comparative matrix of crowdsourced (Mapillary) versus standardized (Google Street View) imagery platforms for continuous canyon modeling.

64

ALGORITHMIC COOLING


Fig. 4.3.5 Optical and geometric noise in crowd-sourced imagery. Raw Mapillary data.

04 R E S E A R C H D E V E L O P M E N T

65


4.3.2 GPS Imprecision and the 2D Street-Front Pivot The cascading effect of urban GPS drift heavily impacted initial geometric projections, causing the ray-casting algorithm to erroneously crop adjacent facades. To eliminate severe horizontal cropping errors, the methodology shifted from isolating single buildings to capturing entire continuous 2D “street fronts.” Because urban microclimate evaluation depends on the proportional surface area of materials rather than absolute metric heights, the pipeline was recalibrated to snap camera positions using geometric rules rather than relying solely on raw GPS. After mapping stations to OSM, the camera XY coordinates for the Inverse Perspective Mapping (IPM) are snapped using three distinct geometric rules: Trajectory Smoothing: Vehicle paths were mapped to an ideal centerline. In narrow streets (e.g., 9m width), the sampling node is mathematically forced to the street center to equalize viewing distances for both facades. Proximity Thresholds: Where the canyon is wider, a 4.5 m standoff is enforced if the initial GPS lies closer than 4.5 m to an OSM facade. Semantic Anchoring: The algorithm compared sky-ratios on opposite facades to center the perspective. Paired 03 crops: if sky fractions differ by ≥ 0.15 and the no-sky side is ≤ 0.20, the camera walks 1–4 m toward that wall, never closer than 2.5 m. Visual inspection of T415 and T416 suggested that the sky-gap adjustment (alongside informal window alignment during calibration phases) most consistently improved the rectified front. Centering in narrow streets was similarly stable. Conversely, the 4.5 m floor yielded mixed results: while it successfully reduced extreme proximity warp on true street walls, it occasionally skewed the IPM when the nearest OSM edge was a sliver or an incorrect plane rather than the photographed facade. To prevent extreme distortion, Script 3 actively discards captures closer than 2 m rather than attempting to translate them to a functional distance. Furthermore, while an experimental window-scale shift was tested during calibration, it was excluded from the final production snap.

66

ALGORITHMIC COOLING


Table 4.3.6: Prevalence of geometric constraints applied during camera positioning. Percentages represent the application rate of each rule per urban tile.

30

m

24

18

12

6

0 30

24

18 Fig. 4.3.7 Qualitative improvement of street fronts post-calibration. (a) Initial geometric projection based on raw GPS positioning, exhibiting severe perspective skew and texture warping. (b) Corrected output demonstrating the combined effect of sky-gap alignment, narrow street centering, and proximity standoffs. Empirical inspection confirms this integrated approach significantly reduces spatial distortion.

04 R E S E A R C H D E V E L O P M E N T

12

6

0

67


4.3.3 Spatial Filtering and Data Viability Raw street-level imagery frequently contains dynamic noise, temporary structures, and urban voids that would corrupt downstream microclimate calculations. To guarantee data integrity, the pipeline evaluates every captured frame through a strict, four-step filtering protocol: Spatial Proximity Limits: Target nodes are automatically discarded if the building footprint is impractically close (under 2 meters), falls beyond the maximum reliable depth, or if the captured visible facade width is less than 6 meters. Foreground Occlusion Masking: Dynamic noise (vehicles, pedestrians) and organic elements (street vegetation) are isolated via semantic segmentation and masked out. Anomaly Rejection: The algorithm actively identifies and discards non-representative building states, specifically filtering out temporary construction scaffolding or exposed building interiors. Minimum Viable Data Threshold: This is the critical quality-control failsafe. After all occlusions and anomalies are masked, the system calculates the remaining valid architectural pixels. If the usable facade area falls below 25% of the total image, the node is deemed statistically unreliable and entirely discarded. For validated images exceeding this 25% threshold, material proportions are calculated strictly from the visible pixels. Table 4.3.8 Data attrition matrix detailing the rejection rates of undistorted frames across tested urban tiles. Rejections are categorized by spatial discrepancies (OSM noise) and unresolvable visual impediments (Obstruction noise).

68

ALGORITHMIC COOLING


Fig. 4.3.9 Validated facade dataset postfiltering. Isolated architectural surfaces that successfully passed all spatial and viability thresholds. Outputs are stored in an R2 cloud bucket. 04 R E S E A R C H D E V E L O P M E N T

69


4.3.4 Material Classification and AI Semantic Segmentation Following spatial filtering, the isolated architectural facades required semantic material classification to extract proportional surface data for the thermodynamic grid. After testing multiple state-of-the-art visionlanguage models, Qwen3-VL was selected as the primary segmentation engine, guided by targeted prompts generated via GPT-4.1 Mini and baseline semantic masking. While Qwen3-VL maps spatial geometry well, testing revealed a major limitation: the model relies primarily on color rather than surface texture. This caused varying levels of accuracy across different material categories: Concrete, Stone, and Stucco (90% confusion rate): The model severely struggled to differentiate between these materials, exhibiting a near 90% inaccuracy rate when attempting to isolate them. Because the model reads color profiles rather than tactile texture, these light-colored, matte surfaces were continuously mixed. Glazing vs. Metal (< 30% confusion rate): Misclassification between glass and metallic surfaces peaked at a maximum of 30%. This error was primarily driven by deep shadows or extreme reflections in the imagery, which the model erroneously segmented as dark metal instead of shaded glass. Brick Masonry (80% / 50% accuracy): The extraction accuracy for brick was highly dependent on pigmentation. Darker, high-contrast brick was successfully isolated with nearly 80% accuracy. However, lighter brick variants suffered a 50% confusion rate, most frequently misclassified as stone. Wood and Organics (Negligible): Wood detection carried almost no statistical weight in the pipeline. It was typically confined to isolated architectural elements (e.g., doors) or ignored entirely. Overall, the data confirms that while AI segmentation effectively separates transparent elements (glass) from opaque mass (brick/mineral), fine-grain textural differentiation remains a systemic limitation.

70

ALGORITHMIC COOLING


Table 4.3.10 Evaluation and benchmarking matrix of selected computer vision and visionlanguage models (VLMs) across inference speed, hardware constraints, and material classification accuracy.

Fig. 4.3.11 Cross-model validation. (a) Gemini segmentation, (b) original orthophoto, (c) local ComfyUI pipeline. Both models show high spatial agreement in isolating fenestration (cyan) from the main stone mass (yellow).

Fig. 4.3.12 Multi-material segmentation. (a) Gemini vs. (b) ComfyUI. Despite minor deviations in complex textures (e.g., ground floors), overall proportional material areas align closely, validating the local pipeline.

(a)

(b)

(c)

(a)

(b)

04 R E S E A R C H D E V E L O P M E N T

71


05 Design Development This chapter presents the development of the research from proofof-concept experiments to the formulation of a scalable assessment framework for urban heat analysis. It begins by investigating the influence of vertical surface materials on the urban microclimate through both field studies and digital experiments, establishing the relationship between material properties, surface temperature, and pedestrian thermal conditions. Building on these findings, a comprehensive Material Catalogue is developed to compile the thermo-physical and radiative properties of common urban construction materials relevant to the London context. The chapter then introduces the Automation Pipeline, which integrates material data with urban geometry and environmental parameters to enable rapid, early-stage evaluation of urban heat performance. Together, these stages transform isolated experimental observations into a structured, data-driven workflow that supports informed material selection and evidence-based design decisions for mitigating the Urban Heat Island effect.

Fig. 5.1.1 Vertical stratification of urban data layers in the custom web portal. The exploded view demonstrates the integration of raw spatial geometry, AI-generated material masks, and microclimate simulation results within a single, unified coordinate system.


05 D E S I G N D E V E L O P M E N T

73


5.1 Surrogate Model

A single urban-canyon simulation required approximately 40 seconds to complete in EnergyPlus. Although suitable for a small case scenario of a canyon, this computational demand becomes impractical when evaluating numerous material and geometric configurations at the city scale. A machine-learning surrogate model was therefore trained using the simulation dataset to approximate the EnergyPlus results and provide rapid surface-temperature predictions. This approach retains the relationships learned from the physics-based simulations while substantially reducing the time required for large-scale analysis. 5.1.1 Surrogate Model Training Pipeline To develop an early-phase heat prediction tool, a parametric workflow was established in Grasshopper. The generation of diverse building permutations was automated using Anemone, while physical thermal simulations for each iteration were executed via OpenStudio and EnergyPlus within the Honeybee environment. The resulting comprehensive dataset was subsequently utilized to train a machine learning surrogate model, enabling rapid and computationally efficient surface temperature predictions.

Simulation

Fig. 5.1.3 Pipeline for training Surrogate Model

74

ALGORITHMIC COOLING


Fig. 5.1.2 Surrogate Model- a Case Scenario

Training Dataset

05 D E S I G N D E V E L O P M E N T

Prediction Model

75


5.1.2 Grasshopper Workflow and Machine Learning The parametric model consisted of a central building divided into façade grids of approximately 3 × 3 m, surrounded by context buildings and streets. This configuration captured the four principal façade orientations and their corresponding urban canyons within a single model. The complete setup was rotated through different angles to generate data for a range of street orientations. Weather data were obtained from the London Weather Centre–St James’s Park EPW file (037700),1 selected because of its central London location. The initial simulations focused on 29th June, identified as the hottest day in the selected weather file, to examine material performance under peak thermal conditions. The central and surrounding buildings were modelled as Honeybee Rooms to account for the influence of surrounding surfaces on the thermal behaviour of the central building. Once the parametric workflow was established, multiple configurations were generated using an automated loop. The resulting simulation data were recorded and transferred to LunchBox ML to train the surrogate model for rapid surface-temperature prediction.

Fig. 5.1.4 Surrogate Model Parametric Workflow

1 Lawrie and Crawley, “Development of Global TMYx,” London TMYx.2004–2018 file.

76

1. Setting a Boundary 2. Setting the domain of the Building, street and context 3. Setting the height of the building 4. Setting the height of the context 5. Randomly shuffling the context density 6. SVF Simulation 7. Thermal Simulation 8. Iteration in Loop creating different case scenarios ALGORITHMIC COOLING


1

2

3

5

7

05 D E S I G N D E V E L O P M E N T

4

6

8

77


5.1.3 London-Informed Parameter Domains Each simulation iteration varied building dimensions, street width, context-building geometry, surrounding urban density, street orientation, and façade materials. The ranges assigned to these parameters were informed by London’s building regulations, and commonly observed urban morphology. This ensured that the generated configurations represented plausible conditions within London. The material palette was similarly derived from façade materials commonly found across London’s built environment. Fourteen vertical façade materials were included, with each material represented in its original, lighter, and darker colour variants. These variations captured the influence of colour on solar absorptance and reflectance while retaining the underlying thermal characteristics of each material. The complete list of materials and their corresponding properties is provided in the index.

1

2

3

4

5

6

7

8

9

10

11

12

13

78

14

Fig. 5.1.5 London facavde material palette 1) Brick (O), (L), (G) 2) Aluminium (O), (L), (G) 3) Concrete (O), (L), (G) 4) Steel (O), (L), (G) 5) Glass (O), (L), (G) 6) Douglas Fir Wood (O), (L), (G) 7) Terracotta (O), (L), (G) 8) Limestone (O), (L), (G) 9) Granite (O), (L), (G) 10) Cement/Mortar (O), (L), (G) 11) Asphalt (O), (L), (G) 12) Slate (O), (L), (G) 13) Plaster (O) 14) Concrete Tile (O), (L), (G)

ALGORITHMIC COOLING


Fig. 5.1.6 Parameter Domain Context Height Range: 4m-50 m Context Width: 8-30m Context Length: 10-40m Building Height: 4-50m Building Width : 8-20m Building Length:10-30 m Street Width: 4-40m Rotation: 0-180 deg

Context

05 D E S I G N D E V E L O P M E N T

Building

Street

79


5.1.4 Training Datapoints The workflow was designed to maximise data generation while limiting the number of simulation iterations. Each iteration recorded hourly results from gridded pixels across four façades over a 24-hour period. Each data point comprised eleven input variables, including time step, air temperature, grid coordinates (x, y), orientation, sky-view factor, and five thermal properties, with surface temperature defined as the prediction output. During the initial stage, approximately 100 iterations generated 213,238 data points for surrogate-model training. Future development will extend the process to 1,000 iterations to increase the diversity and coverage of the training dataset, with the aim of improving the model’s predictive accuracy and generalisability.

Fig. 5.1.7 100 Iterations for predicting Surface Temperature

80

ALGORITHMIC COOLING


05 D E S I G N D E V E L O P M E N T

81


Fig. 5.1.8 Data Hierarchy for the Surrogate Model 4 faces × 15 pixels × 24 timesteps = 1440 lines → single ML.net input, 500 simulations × 4 facades × ~100 pixels × 24 timesteps — conceptual scale, not fully enumerated 82

ALGORITHMIC COOLING


05 D E S I G N D E V E L O P M E N T

83


5.1.5 Surrogate Model Validation and Error Metrics The dataset generated through the parametric workflow was used to train a LightGBM Regression model within LunchBox ML. Following training, the model was validated by comparing its surface-temperature predictions with the corresponding Honeybee - EnergyPlus simulation results. Preliminary validation produced an R2 of approximately 0.75, an MAE of 1.12°C, and an RMSE of 1.02°C, indicating an average prediction error of approximately 1.07°C. The results suggest that the model captured meaningful relationships between urban geometry, environmental conditions, material properties, and façade surface temperature while requiring substantially less computation than physics-based simulation. Future development will expand the training dataset to approximately 1,000 simulations to improve predictive accuracy and generalisability.

Fig. 5.1.9 24 hr comparision of Surface temperature prediction by surrogate model Vs Honeybee simulation 84

ALGORITHMIC COOLING


Fig. 5.1.10 Surface temperature shown by Honeybee Simulation-Time: 5pm Grid 44 ST: 29.4

Fig. 5.1.11 Surface Temperature Prediction by Surrogate Model: Time: 5pm Grid 44 ST: 28.7 05 D E S I G N D E V E L O P M E N T

85


5.2 Material Data Acquisition

Duallity of the process Material data acquisition is a dual-scale process, operating across two contrasting levels of spatial abstraction: transitioning from the macro urban-metropolitan scale down to micro-level pixel analysis. The initial phase operates at the urban scale through an automated pipeline utilizing spatial coordinates, trigonometry, and geometric transformations. It acquires and positions raw street-view imagery within the OpenStreetMap environment, aligned with the EPSG:27700 (British National Grid) coordinate system. Developed in Python, the pipeline integrates the Google Street View API and Google Tiles API using open-source geospatial libraries—specifically OSMnx, GeoPandas, and Shapely. The second phase operates at the pixel scale, focusing on automated material recognition. Maintaining the pixel transformation from the raw oriented images and employing the Vision-Language Model Qwen3VL, it analyzes the dataset to segment each facade into color-coded material masks. Implemented in ComfyUI, this pipeline preserves perpixel information and spatial alignment from the urban phase.

86

ALGORITHMIC COOLING


Figure 5.2.1 Hybrid Python-ComfyUI pipeline for geospatial facade extraction and VLM-based material segmentation.

05 D E S I G N D E V E L O P M E N T

87


5.2.1 Spatial Sampling and Panoramic Data Acquisition To manage large-scale geospatial queries and optimize computational performance across the metropolitan region, the target area is structured using a grid-based spatial partitioning scheme (tiling). Within each tile, the street network centerlines are extracted from OpenStreetMap (OSM) and discretized into sampling nodes at fixed spatial intervals of 10 meters. To filter out non-built locations (such as open fields or motorways), a spatial proximity check applies a 30-meter buffer zone around each node to detect nearby vector building footprints. Nodes intersecting with building geometry are flagged as active sampling points. For each active sampling point, the pipeline queries the Google Street View API to locate the nearest panorama camera position. Once confirmed, the system executes two concurrent acquisition tasks: Image Downloading (python download_spheres.py): The raw 360° equirectangular panoramas are retrieved and stored directly in cloud storage (01a_panoramas_images in R2 Buckets). Metadata Extraction (python 1b_patch_headings.py): The exact panorama metadata—including the unique Panorama ID (pano_id), exact camera coordinates, capture date, and original camera heading (orientation relative to true North), roll, rotate, is parsed and indexed into the central SQL database (01_panoramas).

Fig. 5.2.2 Spatial network visualization representing the final output of the combined download_spheres.py and 1b_patch_headings.py scripts.

88

ALGORITHMIC COOLING


05 D E S I G N D E V E L O P M E N T

89


5.2.2 Panoramic Reconstruction Raw image tiles are reconstructed into a unified 360° equirectangular matrix, transforming raw image data into spatially aware pixels that each carry an exact UV coordinate and 3D viewing direction alongside its color.

{ “pano_id”: “CAoSLEFGMVFpcE12S3pSOTNmR0xYd2pxYjh”, “tile_id”: “Tile_415”, “spatial_reference”: { “epsg_27700_bng”: { “easting”: 530142.15, “northing”: 181452.80 } }, “camera_pose”: { “heading”: 142.65, “pitch”: -0.85, “roll”: 0.42, “camera_height_m”: 2.5 }, “temporal_info”: { “capture_date”: “2023-08”, “download_timestamp”: “2026-08-07T12:28:13Z” }, “contextual_metrics”: { “sampling_node_id”: “OSM_NODE_8923410”, “nearest_building_distance_m”: 4.12, “active_buffer_30m”: true } }

90

ALGORITHMIC COOLING


Fig. 5.2.3 Projection Type: Spherical (360°×180°) Aspect Ratio: 2:1 Output Resolution: 4096×2048” px” Tile Grid Structure: 8×4 raw tiles (512×512” px” per tile) Angular Grid Resolution: 22.5°×22.5° per grid cell (16 cols × 8 rows)

05 D E S I G N D E V E L O P M E N T

91


Fig. 5.2.4 Urban “barcode” panorama. Extracted facade strips and their corresponding material metadata are arranged in sequential columns, providing a compressed, continuous visualization of the processed dataset.

92

ALGORITHMIC COOLING


05 D E S I G N D E V E L O P M E N T

93


5.2.3 Vector-Aligned Camera Orientation and FOV Adjustment To establish a structured spatial link between street-level sampling nodes and building geometry, the pipeline first decomposes OpenStreetMap (OSM) building polygons into individual, street-facing facade segments via 3_extract_facades.py. Each extracted segment is assigned a unique identifier (facade_id) and topologically associated with its corresponding street segment (street_id). Key geometric attributes—including start and end spatial coordinates, segment length in meters, and orientation vectors—are calculated and indexed in the central database (facade_registry). Once facade segments are identified, the camera heading is calculated perpendicular (90°) to the facade baseline (facing left or right of the street trajectory). This orthogonal alignment ensures a direct elevation view while minimizing perspective distortion. To capture full building heights across diverse street widths, camera framing combines a fixed 13o upward pitch with a distance-adaptive Field of View (FOV): - FOV 135° for distances - FOV 110° for distances - FOV 90° for distances

d<6m 6 m < d < 15 m d > 15 m

Depending on the orthogonal distance between the camera position and the wall plane, the FOV automatically switches between three predefined values. This dynamic adjustment ensures that the full height of multi-story facades is captured even in narrow street canyons, while preserving consistent scale and framing across the dataset.

94

(a)

Fig. 5.2.5 Distance-adaptive Field of View (FOV) extraction logic. (a) Plan diagrams illustrating dynamic FOV adjustments (90°, 110°, and 135°) triggered by varying street widths. (b) 3D spatial intersection of the camera’s viewing frustum with the target OSM facade, utilizing orthogonal alignment and a fixed 13° upward pitch. (c) The resulting extracted imagery, demonstrating how dynamic FOV thresholds ensure consistent vertical scale and full-height building capture across diverse urban canyons. ALGORITHMIC COOLING


(b)

(c)

FOV 90 05 D E S I G N D E V E L O P M E N T

FOV 110

FOV 135 95


Fig. 5.2.6 Principle of Inverse Perspective Mapping (IPM) for facade rectification. (a) Rectified projection. The horizon line remains fixed at camera height (Z = h_cam), while pixels above and below undergo row-dependent perspective stretching.

5.2.4 Perspective Rectification and Metric Scaling To transform the wide-angle perspective crops generated by the raycasting engine into orthographic facade elevations, the pipeline executes an Inverse Perspective Mapping (IPM) routine via 4_masking.py.

(b) Diagrammatic representation of the IPM routine intersecting a 3D building volume. Virtual boundary rays (white lines) are cast from the camera origin (X) towards the exact geometric limits of the OSM footprint (red outline), defining the precise spatial bounds of the target facade.

Virtual boundary rays are cast from the camera coordinate toward the OpenStreetMap (OSM) footprint geometry. The spatial intersection of these rays with the facade baseline defines the exact physical left and right bounds of the target building segment. Using these intersection coordinates alongside the known camera pose (camera height: 2.5m, pitch:13°), the raw perspective image is un-projected onto a planar 3D canvas, mathematically removing lens and tilt distortion without requiring prior 3D building height data. Finally, each rectified image is normalized to a standardized metric scale: 1m = 30 pixels By anchoring pixel columns to exact ray-collision points on the vector footprint, this transformation reconstructs facade geometry in its true physical proportions, producing spatially calibrated outputs ready for downstream material segmentation.

96

(c) The resulting orthorectified image projection (center) compared against the original distorted wide-angle crop (left). By projecting the raw pixels onto a planar 3D canvas defined by these boundary rays, the process mathematically eliminates lens curvature and tilt distortion, producing a scaled, true-to-proportion elevation suitable for material segmentation.

ALGORITHMIC COOLING


+

+

“width_px”: 797 { "quality": "ok", "camera_xy": [530323.938, 180819.011], "camera_heading_deg": 143.51, "dynamic_pitch": 13.0, "dynamic_fov": 110.0, "start_xy": [530340.794, 180818.865], "end_xy": [530319.284, 180803.277], "length_m": 26.567, "width_px": 797, "height_px": 750,

(a)

"depth_m": 10.009,

(b) “length_m”: 26.567

}

30m

(c)

FOV 110 05 D E S I G N D E V E L O P M E N T

Undistorted

Scale city-wide 97


5.2.5 Pixel-Level Semantic Segmentation Following the orthorectification of the facade images (standardized to 460 x 720 pixels), the data is routed through a specialized visual-language processing workflow built in ComfyUI. To accurately extract the physical properties of the buildings, we process the images in three distinct steps: filtering out heavy occlusions, removing urban noise (sky, cars, and pedestrians) to isolate the building, and finally generating a color-coded map of all facade materials.

Step 1: Quality Control and Occlusion Filtering The initial stage utilizes the Qwen3-VL vision-language model to evaluate the visual integrity of the input image. The system acts as a strict automated gatekeeper, applying an ACCEPT or REJECT filter to discard images that are incorrectly captured (e.g., interior views) or heavily blocked by urban obstructions such as scaffolding (>50%) or foliage (>50% greenery). Step 2: Building Isolation and Background Removal Once an image is accepted, it undergoes targeted masking to isolate the pure architectural geometry. Grounding DINO, paired with the Segment Anything Model (SAM), receives the text prompt “sky” to accurately identify and remove the background. Simultaneously, a You Only Look Once (YOLO) object detection model, trained on the COCO dataset, detects and masks dynamic foreground elements like cars and pedestrians. Step 3: Material Classification and Mapping In the final phase, ChatGPT (gpt-4.1-mini) dynamically constructs semantic prompts based on the architectural context. These targeted prompts guide the Sa2VA framework (a hybrid architecture combining Qwen3-VL and SAM2), which executes the precise pixel-level segmentation. The resulting output is a clean, color-coded spatial map categorizing all distinct facade materials across the building elevation. 98

Fig. 5.2.7 Three-stage semantic segmentation workflow: (1) raw orthorectified input, (2) automated building isolation, and (3) pixel-level material classification mask

ALGORITHMIC COOLING


05 D E S I G N D E V E L O P M E N T

99


5.2.6 Spatial Discretization and Pixel Enrichment Following material segmentation, the orthorectified facade is geometrically partitioned using a 3x3m spatial grid. Crucially, rather than downsampling the high-resolution segmentation into dominant material tiles, this step functions as a pixel enrichment process. Individual pixels retain their precise material classification and intrinsic color, quantified on a material brightness index ranging from dark (0) to light (1), while being supplemented with localized environmental data from the grid. As the data flows through the pipeline, the 3×3m grid acts as an informational overlay. Every pixel falling within a specific grid segment inherits two key contextual attributes: Sky View Factor (SVF): A localized SVF value calculated for that specific 3×3m patch, quantifying the proportion of the sky visible from that elevation. UV Information Grid: Exact spatial coordinates anchoring that specific facade segment back to the global 3D matrix. By preserving the high-fidelity material types and their specific surface tones (from dark to light) at the pixel level, while simultaneously tagging each pixel with the macro-spatial data (SVF and UV location) of its parent 3×3m tile, the pipeline perfectly aligns the dataset for the subsequent phase. This dual-resolution architecture allows the downstream surrogate model, which evaluates thermal performance natively on a 3×3m dimensional logic.

Fig. 5.2.8 Dual-resolution data architecture on a 3x3m spatial grid. The visualization demonstrates how pixel-level material and brightness values are systematically enriched with contextual Sky View Factor (SVF) and precise UV spatial coordinates within each grid segment. 100

ALGORITHMIC COOLING


05 D E S I G N D E V E L O P M E N T

101


Fig. 5.2.9 Semantic “barcode” panorama. AI-generated material segmentation masks and their metadata arranged sequentially, visualizing the continuous distribution of urban materials across the processed dataset.

102

ALGORITHMIC COOLING


05 D E S I G N D E V E L O P M E N T

103


06 Design Proposal To integrate urban material data with a thermal prediction model for large-scale urban thermal analysis, an open web portal is developed. The objective of the portal extends beyond surface temperature prediction, aiming instead to deliver analytical insights that compare the impacts of different material composition schemes. Through this workflow, the portal provides actionable, cityscale thermal insights that were previously unavailable in any design and planning stages.


6.1 The Analytic Portal

6.1.1 Bridging Urban Surface Data and Thermal Analysis To map the thermal impact of urban vertical materials, an interactive web portal was developed to transform raw spatial data into accessible information. A Machine Learning (ML) surrogate model serves as the core simulation engine to predict thermal behavior, while facade imagery and material masks, pre-processed automatically and stored across a SQL database and object storage, provide the empirical urban data for thermal analysis. The portal stands as an integrated platform bridging urban data with thermal analysis, effectively bypassing labor-intensive 3D modeling and computationally demanding energy balance calculations. Ultimately, this framework provides rapid urban-scale thermal analytics to address the central research question: Can the thermal impact of urban vertical surfaces be mapped and answer, how hot is London, and how cool can it be?

Fig. 6.1.1 Diagram illustrating the structure of the project. Machine Learning model and facade images serves as inputs for the web portal to analyse thermal performance of vertical materials.

106

ALGORITHMIC COOLING


06 D E S I G N P R O P O S A L

107


6.1.2 The Analytic Portal Framework The frontend web application is built using a JavaScript framework, integrating open-source libraries such as MapLibre and OpenStreetMap for spatial context, alongside Three.js for interactive visualization, such as rendering vertical surfaces, heat particles, and heat terrain. Apache ECharts was implemented for interactive analytical graphs.

Fig. 6.1.2 System Logic Diagram illustrates the inference ML model, backend api, and object storage serves as input for the frontend portal, while the portal includes several libraries to transform input surfaces into interactable urban thermal simulation.

The inputs for the frontend include an inference of the ML surrogate model for thermal prediction, alongside a backend API node receiving HTTPS requests from the portal and retrieving data from the SQL database. After acquiring data, the portal then uses the URL metadata in each record to retrieve facade images and material masks from the R2 object storage. This backend and frontend structure maximizes scalability, as individual modules are constantly updated throughout the design research to improve overall accuracy and performance.

108

ALGORITHMIC COOLING


06 D E S I G N P R O P O S A L

109


6.1.3 Core Simulation Framework To map thermal behavior of urban material, the simulation workflow is divided into three sequential steps. The process begins with realtime 2.5D Sky View Factor (SVF) and 3D View Factor (VF) computation. Next, the SVF, along with other input features, is fed into the ML surrogate model, which was converted from ML.NET into the ONNX format, to predict surface temperatures. Using the predicted surface temperatures and the previously derived view factors, Radiant Load is calculated through an energy balance formulation. By separating the time-consuming geometric computation and thermal prediction process, SVF and VF are evaluated only once per site query, allowing users to rapidly recalculate Surface Temperature and Radiant Load whenever surface materials are altered.

6.1.4 Simulation Criteria Guided by early-phase experiments, the criteria to determine “how hot the site is” is Surface Temperature and Radiant Load. Surface Temperature is widely used as an objective when measuring Surface Urban Heat Island, since it is the most direct observatable criteria to map the direct relationship of material and their thermal behavior. On the other hand, Radiant Load is a criteria that describe how much heat is releasing to the street at the moment, including shortwave reflection, longwave emission and reflection. The operational formula: RL = (1−α)·SW_in + εσT_s⁴ + (1−ε)·LW_in

Fig. 6.1.3 (Left) The Diagram shows the logic behind 2.5D SVF and 3D VF calculation. Fig. 6.1.4 (Right) The system logic diagram illustrates the simulation framework from geometric computation to heat prediction & calculation. With identical inputs, ML surrogate model mainly bypass the energy balance calculation for faster calculation speed.

110

ALGORITHMIC COOLING


06 D E S I G N P R O P O S A L

111


04 Portal // Methods 6.1.5 Key Features Building upon the technical foundation, the analytical portal is structured into six sequential steps to facilitate data-driven analysis and informed decision-making at the urban scale: 1. Query Facade Data: Users can select a site location and query facade data from the backend server through an API request. The facade data is pre-processed and can be updated through our previous data acquisition and post-process pipeline. 2. Predict & Calculate Heat: Heat simulation is structured into three steps: real-time Sky View Factor (SVF) and View Factor (VF) simulation, Surface Temperature (ST) prediction through an ML surrogate model, and Radiant Load calculation based on previous simulation results. The separation between geometric and energy balance computation allows later stages to be more efficient.

STEP 1

Query Façade Data

STEP 4

Identify Heat Zones

3. Visualise in 3D: To inspect the simulation result, users can expand the selected layers into an exploded view, or use the time slider to simulate the thermal behavior of urban surfaces throughout a day. 4. Identify Heat Zones: To effectively identify heat zones, users can switch between metrics and display modes, from day to night, surface temperature to radiant load, heat map to heat particle, and 2D sampling to 3D heat terrain. 5. Make a Change: To change urban material, users can switch between selection modes and display metrics to select target surfaces. Using the Material Composition graph, users can select individual or all materials to change to another building surface material, or even to change colour. 6. Compare Impact: Using the Comparison Panel, users can easily visualise criteria values with line graphs and diamond charts, allowing comparison before and after changing the urban material. Together, these methods provide an accessible platform to explore city-scale surface heat performance, effectively bridging the gap between raw street-level imagery data and actionable urban vertical thermal analysis.

112

Fig. 6.1.5 The workflow diagram illustrate the sequential procedures between portal and analytic mode. Once all steps are done in portal (step 1 to step 3), analytic mode will be enabled (step 4 to step 6) to provide insights about urban surface thermal impact.

ALGORITHMIC COOLING


Algorithmic Cooling # 1

STEP 2

Predict & Calculate Heat

STEP 3

Visualise in 3D

STEP 5

Make a Change

STEP 6

Compare Impact

06 D E S I G N P R O P O S A L

113


6.2 Step 1: Query Facade Data

Step 1: Query Facade Data To query facade data from the backend server, users can follow the guided steps in the left-hand workflow panel. First, the user defines a square site ranging from 200 to 1,000 meters per side, with the simension tailored to the client device’s commputational capacity. Confirming the selection triggers an API request to retrieve the corresponding facade records from the database and object storage (See Apendex 03). The selected site range directly dictate the volume of cached data and WebGL rendering process. For instance, a 500-meter site contains roughly 1,250 facades, each associated with two images (a facade image and a material mask). This totals around 2,500 images, resulting in approximately 1.5 GB of RAM and 1.3 GB of VRAM usage under worst-case conditions.

1. Select

2. Query

{ “end_lat”: 51.51261170623905, ”end_lng”: -0.12647970224178728, ”facade_id”: ”way/186337052_NW”, ”finished_at”: ”Sat, 08 Aug 2026 16:28:28 GMT”, ”img_bottom_m”: 0.0, ”img_top_m”: 30.0, ”is_valid”: true, ”length_m”: 13.603, ”material_crop_url”: ”https://materials.algorithmiccooling.com/06_facade_materials/orig/way_186337052_NW__T415_0160_right.png”, ”material_mask_url”: ”https://materials.algorithmiccooling.com/06_facade_materials/seg/way_186337052_NW__T415_0160_right.png”, ”normal_az_deg”: 320.5, ”side”: ”right”, ”start_lat”: 51.5126870986071, ”start_lng”: -0.12632539949978963, ”station_id”: ”T415_0160”, ”status”: ”PASSED”

Reset Enter Analytic

} Range

Photos

Masks

Time (Second)

RAM

VRAM

500 m

1253

1253

20 s

1.2 GB

1.3 GB

1000 m

5000

5000

210 s

1.7 GB

1.4 GB

* Test Coordination: {51.5131, -0.1206}. Grid Count SVF VF 3.2 ST 3.3 RL * TheRange listed figures are estimated3.1and will vary 3.1 according to different coordination, device, 500and m internet speed.” 153,735 3.5 s 18.0 s 20.0 s 0.7 s 1000 m

511,605

Altered Material

114

50.8% Brick + 23.1% Stone

7.0 s

65.7 s

69.7 s

2.7 s

Modified ST

Delta

Impact %

Stone

48.6 °C

-5.8 °C

-10.60%

Limestone

48.9 °C

-5.4 °C

-9.90%

Plaster

50.0 °C

-4.4 °C

-8.00%

50.5 °C

-3.8 °C

-7.00%

50.6 °C

-3.7 °C

-6.90%

Aluminium Terracotta

54.3 °C

Caption 6.2.1 A single facade data tree returned by the API request, showing its metadata fields in JSON format. Table. 6.2.1 Tested image count and time with estimated operational requirement in different query scales. Fig. 6.2.1 The workflow interface used to query facade metadata from the backend via an HTTPS API request.

ALGORITHMIC COOLING


Map Tools

Save View

Layer Control

Legend

06 D E S I G N P R O P O S A L

115


Fig. 6.2.2 Selecting a site location and adjusting its boundary size on the map. Fig. 6.2.3 Facade Images from the automated post-processing pipeline from previous stage was retrieved through the backend API and served from object storage.

116

ALGORITHMIC COOLING


Fig. 6.2.4 The processed street-level image layer viewed at street level. Fig. 6.2.5 The processed material mask layer viewed at street level.

06 D E S I G N P R O P O S A L

117


6.3 Step 2: Predict & Calculate Heat

Step 2: Predict & Calculate Heat To simulate heat from the processed material masks, the workflow is structured into three sequential steps based on the core simulation framework. First, the Sky View Factor (SVF) and View Factor (VF) simulations are executed as a single geometric computation step. Next, the surrogate model is deployed to predict the Surface Temperature (ST). Finally, the Radiant Load (RL) calculation is executed based on the predicted Surface Temperature and the geometric View Factors. This hybrid separation between geometric computation, surrogate prediction, and mathematical calculation allows the portal to accurately cache surface geometries. Consequently, when materials are altered in later stages, the system bypasses the need to re-execute the timeconsuming geometric calculations.

3.1. Grid Size 3.1. SVF & VF

3.2. ST

3.3. RL Step Info Range

Photos

Masks

Time (Second)

RAM

VRAM

500 m

1253

1253

20 s

1.2 GB

1.3 GB

1000 m

5000

5000

210 s

1.7 GB

1.4 GB

Range

Grid Count

3.1 SVF

3.1 VF

3.2 ST

3.3 RL

500 m

153,735

3.5 s

18.0 s

20.0 s

0.7 s

1000 m

511,605

7.0 s

65.7 s

69.7 s

2.7 s

* Test Coordination: {51.5131, -0.1206}. 50.8% Brick + * The listed figures are measured in theModified test coordination and will varyImpact according to Altered Material ST Delta % 23.1% Stone different coordination’s coverage and device computational capability.” Stone

48.6 °C

-5.8 °C

-10.60%

Limestone

48.9 °C

-5.4 °C

-9.90%

Plaster

50.0 °C

-4.4 °C

-8.00%

50.5 °C

-3.8 °C

-7.00%

50.6 °C

-3.7 °C

-6.90%

Aluminium Terracotta Brick

50.6 °C

-3.7 °C

-6.90%

Wood

51.3 °C

-3.0 °C

-5.60%

Steel

52.2 °C

-2.1 °C

-3.90%

Altered Material

118

54.3 °C

Original Mat. (54% Stone)

Modified RL (w/m²)

Delta RL (w/m²)

499

-61

-10.90%

Steel

505

-55

-9.90%

Wood

518

-41

-7.30%

523

-37

-6.60%

523

-37

-6.60%

Brick

532

-28

-5.00%

Limestone

532

-28

-5.00%

Plaster

560 w/m²

Table. 6.3.1 Sub-divided surface grid counts and the corresponding computational execution times recorded for each step of the simulation workflow. Fig. 6.3.1 The primary user interface utilized during the geometric computation and thermal prediction processes.

Impact (%)

Aluminium

Terracotta

Main Info

ALGORITHMIC COOLING


Surface Temperature Layer

Radiant Load Layer

Legend

06 D E S I G N P R O P O S A L

119


Fig. 6.3.2 The grid division is coloured by the surface UV domain from Step 3.1, serving as a geometric input for the surrogate model. Fig. 6.3.3 The Sky View Factor (SVF) mapped into a color mask layer to visually validate the geometric computation.

120

ALGORITHMIC COOLING


Fig. 6.3.4 The Surface Temperature (ST) heat map generated following the surrogate model prediction in Step 3.2. Fig. 6.3.5 The Radiant Load (RL) heat map produced after the final mathematical calculations in Step 3.3.

06 D E S I G N P R O P O S A L

121


6.4 Step 3: Visualise in 3D

Step 3: Visualise in 3D Before moving into analytics to analyse therrmal impacts, it is crucial to make sure the results are correctly processed. Therefore, an explosion mode is developed for user to inspect layers without having to constantly switch on and off between layers. The time of day slider also allows user to simulate the change of thermal behavior throughout the hottest day in London (29th Jun)1.

1 Lawrie and Crawley, “Development of Global TMYx,” London TMYx.2004–2018 file.

3a. Adjust Time

3b. Explode Layers

Enter Analytic

Fig. 6.4.1 The user interface during the final step in the simulation portal. Simulated layers can be expanded through exploded view mode for simultaneous inspectioon, while an integrated time slider simulates thermal behavior across timesteps throughout a day.

122

ALGORITHMIC COOLING


Surface Temperature

Sky View Factor

Layer Control Material Mask

Facade Images

Legend

06 D E S I G N P R O P O S A L

123


00:00, 29th Jun

02:00, 29th Jun

04:00, 29th Jun

06:00, 29th Jun

08:00, 29th Jun

10:00, 29th Jun

12:00, 29th Jun

14:00, 29th Jun

16:00, 29th Jun

18:00, 29th Jun

20:00, 29th Jun

22:00, 29th Jun

Fig. 6.4.2 Time step simulation for Surface Temperature shows the highest temperature surfaces concentrates on the surfaces that is directly exposed to the sun and vary between different material properties. 124

ALGORITHMIC COOLING


00:00, 29th Jun

02:00, 29th Jun

04:00, 29th Jun

06:00, 29th Jun

08:00, 29th Jun

10:00, 29th Jun

12:00, 29th Jun

14:00, 29th Jun

16:00, 29th Jun

18:00, 29th Jun

20:00, 29th Jun

22:00, 29th Jun

Fig. 6.4.3 Time step simulation for Radiant Load shows the highest temperature surfaces also concentrates on the surfaces that is directly exposed to the sun but vary mainly between albedo and emissivity of different material. 06 D E S I G N P R O P O S A L

125


6.5 Step 4: Identify Heat Zones

6.5.1 Analytic Metric & Display Mode To transform complex thermal analyses into a user-friendly interface, the UI panel is divided into two primary sections. On the left is the Control, Select & Modify Panel, which manages layer presets, selection modes, and material modifications. On the right is the Analytical & Material Composition Panel, which controls analytic metrics, comparison criteria and graphs, and material compositions.

Layer Panel View Preset Time Basis

The layer rendered in the viewport is directly governed by the selected Analytic Metric and Display Mode. Display Mode : View Preset Terrain : Displays heat terrain layer (3D data visualisation) to identify heat zones. Mask : Displays material mask layer to compare change of material. Surface : Displays heatmap (ST) or heat particle (RL) to visualise simulation. Time Basis 24H (Instantaneous) : Renders heatmap or heat particle in 24-hour timesteps. Metric (Aggregated) : Presents summarised thermal metrics computed according to the Time Basis and statistical aggregation settings. Analytic Metric : Time Period Day : Aggregates simulation results during daytime hours. Night : Aggregates simulation results during nighttime hours.

Select & Modify

Criteria Surface Temperature (ST) : Evaluates the temperature of the facade surface. Radiant Load (RL) : Quantifies outgoing thermal radiation emitted and reflected from the vertical facade toward the street canyon. Statistic Aggregation Mean : Calculates the mean value across daytime or nighttime periods. Peak : Displays the maximum value reached during daytime or nighttime periods. Comparison Original : The baseline summarized metric calculated for the entire site boundary or user-selected surfaces. Modified : The updated metric calculated after applying material alterations to the selected surfaces. Delta : The difference resulting from the intervention, where green indicates thermal improvement and orange signifies deterioration.

126

Return Portal

Fig. 6.5.1 The primary user interface for Analytic mode. The diagram illustrates the Peak Surface Temperature during Day Period, displayed using Surface Preset (Heat Map).

ALGORITHMIC COOLING


Analytic Panel Time Period Criteria Statistic Comparison Analytic Graphs

Line Graph

Material Composition

06 D E S I G N P R O P O S A L

127


6.5.2 Heat Particle: Radiant Load To represent the outgoing heat from vertical surfaces into the street, a particle system is introduced to animate and visualize Radiant Load. Based on the calculated values, higher Radiant Load is rendered in yellow, featuring a greater density of particles that escape further from the surface, while lower Radiant Load is colored dark red, characterized by fewer particles positioned closer to the surface.

Heat Particle

Users can toggle between Time Period and Time Basis modes to examine Radiant Load across 24-hour timesteps, as well as distinct Day and Night periods. This method delivers a clear thermal representation, helping users quickly identify the building surfaces that affect pedestrians the most.

Fig. 6.5.2 (Left) The particle visualization of Peak Radiant Load during the Day Period. Fig. 6.5.3 (Top-Right) The particle visualization of Peak Radiant Load during the Night Period. Fig. 6.5.4 (Bot-Right) The particle visualization of 24-hours timestep mode.

128

ALGORITHMIC COOLING


Night Period Radiant Load Peak

10:00, 29th Jun

06 D E S I G N P R O P O S A L

14:00, 29th Jun

18:00, 29th Jun

129


6.5.3 Data Visualisation: Heat Terrain To enable users to quickly identify heat zones, Heat Terrain is implemented as an interactive 3D visualization method. By sampling simulation results across chosen criteria and metrics, values from the vertical facade grid are first projected onto the ground plane. Subsequently, an interpolated 2D continuous field is generated based on the magnitude and spatial proximity of the projected points. Finally, 3D contours and extruded terrain meshes are constructed from this zoned ground field, producing a continuous 3D heat terrain for spatial analysis.

Terrain Mode

3D Heat Terrain

2D Heat Field

Projected Values

Fig. 6.5.5 (Left) The exploded diagram illustrates the progression from sampling the heat field to generating the 3D heat terrain. Fig. 6.5.6 (Top-Right) By selecting Terrain Mode, users can quickly identify Heat Zones across different Time Periods and Criteria, illustrating Day ST Heat Zones. Sampled Values

130

Fig. 6.5.7 (Bot-Right) The Heat Terrain illustrates heat zones evaluated under day Radiant Load criteria and night Radiant Load criteria.

ALGORITHMIC COOLING


Day Period ST Peak

06 D E S I G N P R O P O S A L

131


Fig. 6.5.8 Switching View Preset to Masks allows inspection of urban vertical materials. Fig. 6.5.9 Switching View Preset to Surface allows inspection of urban vertical heatmap or heat particles.

132

ALGORITHMIC COOLING


Fig. 6.5.10 Material mask layer shows urban vertical material compositioon. Fig. 6.5.11 Heat particle layer shows thermal behavior differences between surface materials under day peak Radiant Load.

06 D E S I G N P R O P O S A L

133


6.6 Step 5: Make a Change

6.6.1 Select Surfaces To make changes to the urban material, three selection modes are developed for effectively isolate target surfaces. Users can switch between Single Surface Selection, Box Selection, and Region Selection modes according to different situations. Box Selection allows users to select surfaces in a batch to inspect their thermal performance as well as their material composition. On the other hand, Region Selection mode will automatically switch the display preset to Terrain Mode, which allows users to select heat zones directly based on the sampled data. 6.6.2 Alter Surface Material According to the selected surfaces, Analytic Panel on the right shows the original summarised criteria value and material composition. After inspection, using Select & Modify Panel will allow users to change selected materials to a new surface material, even changing the color. This will trigger automatic recalculation of Surface Temperature and Radiant Load, generating the modified criteria, analytic graphs, and material composition for comparing the impact.

Region Select

A. Replace B. With C. Repaint

Fig. 6.6.1 (Left) Menu of original material and targeted material for altering. Fig. 6.6.2 (Right) Using Region Selection mode allows users to isolate the target Heat Zone. Modify Panel allows material modification along with colour repaint. Fig. 6.6.3 The selected surface temperature heatmap (From Fig. 6.6.2). A. Replace 51% Brick

134

B. Replaced With Wood, Light Paint

Fig. 6.6.4 Using Box Selection mode allows users to isolate target surfaces directly.

ALGORITHMIC COOLING


Selected Region Value

Selected Region Graph

Selected Region Material

Box Select Mode

Fig. 6.6.3

06 D E S I G N P R O P O S A L

Fig. 6.6.4

135


6.7 Step 6: Compare Impact

Using the line graph on the Analytic Panel, the difference between original and modified values is mapped with different colors. Together with the Material Composition graph, the relationship between materials and their thermal impact can be readily established. However, as early experiments showed, there is no single answer for the optimal surface material to use for the whole city. Therefore, a diamond chart is developed to show the tradeoffs. In the test case (Fig. 6.7.2), 50.8% brick and 23.1% stone were altered to light-painted wood, which has a much lower solar absorptance, with an alpha value of 0.2 to 0.3 compared to 0.65 to 0.70 for masonry, alongside lower thermal conductivity and heat capacity. Under these modifications, Day ST, Night ST, and Night RL dropped significantly, while Day RL increased substantially as a tradeoff.

Fig. 6.7.1 The diamond chart shows multi-criteria tradeoffs, showing that while Day & Night ST and Night RL decrease, Day RL increases substantially as a key performance tradeoff. Fig. 6.7.2 After altering surface materials, the system automatically recomputes ST and RL, mapping the differences and impacts using comparative values and graphs.

136

ALGORITHMIC COOLING


Altered Criteria

Original Graph Altered Graph

Altered Terrain

06 D E S I G N P R O P O S A L

137


6.8 Experiment : Material Thermal Impact

6.8.1 How Hot is London? How Cool can it be? To address the central research questions, “How Hot is London?” and “How Cool Can It Be?”, the methodology couples an automated data pipeline with an interactive web portal, allowing users to explore the microclimatic impacts of urban vertical materials. This analytical platform transforms what is typically a static, single-use research pipeline into a dynamic environment for testing diverse urban sites and material compositions. Central London (51.5131, -0.1205) is selected as the primary test site to examine localized heat zones and evaluate comparative material interventions, testing the efficacy of different facade compositions in cooling the urban canyon across two distinct scenarios. 6.8.2 Scenario A: Day Peak Temperature Driven by accelerating climate extremes, the intensity and frequency of heatwaves have increased significantly in recent years. A major challenge for London is the daytime Urban Heat Island effect, during which urban temperatures far exceed those in surrounding rural areas. To address this challenge, daytime peak surface temperature is selected as the primary evaluation criterion. Using the 3D Heat Terrain visualization, a localized thermal hotspot on Southampton Street is rapidly identified, exhibiting an average of 54.3 °C across the selected region and reaching a peak of 59.2 °C on the hottest surfaces.

Alter regioinnal material from 50.8% Brick and 23.1% Stone

138

Fig. 6.8.1 (Left) Exploded view of layers in the selected region. Fig. 6.8.2 (Right) Selecting the Heat Zone to inspect surface temperature regionally. Fig. 6.8.3 (Bot-Left) Material Masks before and after change. Fig. 6.8.4 (Bot-Right) ST Heat Map before and after change.

After change, 73.9% regional material is stone painted light grey (210,210,205).

ALGORITHMIC COOLING


Regional Surface Temperature is 54.3 °C originally.

06 D E S I G N P R O P O S A L

Regional Surface Temperature is 48.6 °C after modification.

139


6.8.3 Scenario A: The Impact from Vertical Surfaces After selecting the target zone in Southampton Street, 50.8% brick and 23.1% stone surfaces were altered to lighter-painted stone (RGB: 210, 210, 205). As a result, the regional Surface Temperature (ST) dropped significantly from 54.0 °C to 48.6 °C, achieving a notable reduction of 5.8 °C (-10.6%). Conversely, critical tradeoffs emerged in the diamond chart (Fig. 6.8.5), which revealed an increase in peak daytime Radiant Load (Day RL Peak) from 768 w/m² to 827 w/m² (+58 w/m², +7.6%). During the experiment, the original materials were replaced with different materials using the same light grey paint to test purely how thermal material properties affect Surface Temperature. Under this controlled baseline, stone and limestone finished with light coatings exhibited the greatest ST reductions. This performance is driven primarily by their physical properties, specifically higher thermal conductivity, density, and specific heat capacity (i.e., high thermal effusivity), which facilitate rapid heat conduction into the wall mass. Consequently, these facades maintain lower daytime surface temperatures while delaying and reradiating heat outward during subsequent hours. Ultimately, surface color remains the dominant factor in dampening peak surface temperatures. In wider streets where heat can release at night, this provides a practical solution to delay heat release into later hours of the day.

Range

Photos

Masks

Time (Second)

RAM

VRAM

500 m

1253

1253

20 s

1.2 GB

1.3 GB

1000 m

5000

5000

210 s

1.7 GB

1.4 GB

Range

Grid Count

3.1 SVF

3.1 VF

3.2 ST

3.3 RL

500 m

153,735

3.5 s

18.0 s

20.0 s

0.7 s

1000 m

511,605

7.0 s

65.7 s

69.7 s

2.7 s

Altered Material

50.8% Brick + 23.1% Stone

Modified ST

Delta

Impact %

Stone

48.6 °C

-5.8 °C

-10.60%

Limestone

48.9 °C

-5.4 °C

-9.90%

Plaster

50.0 °C

-4.4 °C

-8.00%

50.5 °C

-3.8 °C

-7.00%

50.6 °C

-3.7 °C

-6.90%

Table. 6.8.1 Daytime peak Surface Temperature (ST) reductions across different materials under an identical paint coating, demonstrating that stone and limestone achieve the greatest temperature drops.

Brick

50.6 °C

-3.7 °C

-6.90%

Fig. 6.8.5 The line graph shows day ST dropped significantly while night ST increased slightly, and the diamond chart illustrates the tradeoff when altering material to lighter stone, which increases the Day RL peak substantially.

Wood

51.3 °C

-3.0 °C

-5.60%

Fig. 6.8.6 Heat Terrain before the modification.

Steel

52.2 °C

-2.1 °C

-3.90%

Fig. 6.8.7 Heat Terrain after the material change, where the terrain disappeared as an indication of regional cooling.

Aluminium Terracotta

54.3 °C

*All altered material is using the same lighter paint (RGB: 210,210,205). Altered Original Mat. Modified RL Delta RL Impact Material (54% Stone) (w/m²) (w/m²) (%)

140 Steel

Aluminium

499

-61

-10.90%

505

-55

-9.90%

Wood

518

-41

-7.30%

Terracotta

523

-37

-6.60%

ALGORITHMIC COOLING


06 D E S I G N P R O P O S A L

141


6.8.4 Scenario B: Night Peak Radiant Load Due to the cold in the winter, London has historically been built to store heat instead of releasing it, with brown brick and stone serving as the most commonly used building materials. This creates a serious problem for nocturnal heat stress, where summer heatwaves hit the city during the day, and streets cannot cool down because solar energy absorbed during the day is released later at night. To address this challenge, nighttime Radiant Load is selected to evaluate heat zones at coordinates (51.5114, -0.1243), identifying facades that release excessive heat into the street. Since Radiant Load values do not vary as widely as surface temperatures, using Box Selection mode allows users to isolate surfaces directly as indicated by the heat particles. The assessment shows that the average RL stands at 532 w/m² across the whole region, while the selected zone averages 560 w/m² and the single peak surface reaches 590 w/m².

Fig. 6.8.8 (Left) Exploded view of layers in the selected region. Fig. 6.8.9 (Right) Selecting the Heat Zone from heat particles to inspect radiant load regionally. Fig. 6.8.10 (Bot-Right) regional material composition before and after the change.

142

ALGORITHMIC COOLING


Alter regioinnal material from 50.8% Brick and 23.1% Stone

06 D E S I G N P R O P O S A L

After change, 73.9% regional material is stone painted light grey (210,210,205).

143


6.8.5 Scenario B: The Impact from Vertical Surfaces After selecting the target zone on Charing Cross Road, 52.5% stone surfaces were altered to lighter-painted aluminum (RGB: 210, 210, 205). As a result, the regional Radiant Load dropped from 560 w/m² to 499 w/m² (-61 w/m², -10.6%). Most criteria improved, while daytime peak RL stayed relatively the same. During testing with the same light grey paint, nocturnal behavior reversed the daytime trend. Stone and limestone became the poorest performers at night, as their daytime stored heat conducted back outward and radiated into the street canyon. Materials with lower thermal mass, such as wood, cooled faster due to lower heat storage. Aluminum and steel achieved the largest reductions because their low longwave emissivity, between 0.2 and 0.3 versus 0.9 for masonry, caps outward radiative transfer regardless of surface temperature. Range

Masks RAM VRAM Ultimately,Photos both thermal mass Time and(Second) surface emissivity govern nocturnal

500radiant m 1253 1253 20 s GB 1.3 GBwhere release through distinct mechanisms. In1.2narrow streets

1000 m 5000 easily, 210 s 1.7 GB 1.4 GB with trapped heat 5000 cannot escape selecting facade materials

lower thermal mass or lower emissivity provides a practical design

Range Count 3.1 SVF heat3.1 VF solution Grid to reduce nighttime loads.

3.2 ST

3.3 RL

500 m

153,735

3.5 s

18.0 s

20.0 s

0.7 s

1000 m

511,605

7.0 s

65.7 s

69.7 s

2.7 s

Altered Material

50.8% Brick + 23.1% Stone

Modified ST

Delta

Impact %

Stone

48.6 °C

-5.8 °C

-10.60%

Limestone

48.9 °C

-5.4 °C

-9.90%

Plaster

50.0 °C

-4.4 °C

-8.00%

50.5 °C

-3.8 °C

-7.00%

50.6 °C

-3.7 °C

-6.90%

Aluminium Terracotta

54.3 °C

Brick

50.6 °C

-3.7 °C

-6.90%

Wood

51.3 °C

-3.0 °C

-5.60%

Steel

52.2 °C

-2.1 °C

-3.90%

Altered Material

Original Mat. (54% Stone)

Modified RL (w/m²)

Delta RL (w/m²)

Impact (%)

Aluminium

499

-61

-10.90%

Steel

505

-55

-9.90%

Wood

518

-41

-7.30%

523

-37

-6.60%

523

-37

-6.60%

Terracotta Plaster

560 w/m²

Brick

532

-28

-5.00%

Limestone

532

-28

-5.00%

Stone

541

-19

-3.40%

*All altered material is using the same lighter paint (RGB: 210,210,205).

144

Table. 6.8.2 Nighttime peak Radiant Load (RL) reductions across different materials under an identical paint coating, demonstrating that aluminum and steel achieve the greatest radiant load drops. Fig. 6.8.11 The line graph shows night RL drops significantly while day RL remains similar, and the diamond chart illustrates improvements in almost every criterion. Fig. 6.8.12 Heat particles before the modification. Fig. 6.8.13 Heat particles after the material change, where the particles disappear as an indication of regional cooling.

ALGORITHMIC COOLING


06 D E S I G N P R O P O S A L

145


07 Conclusion This chapter synthesizes findings across the individual stages of the research process, discussing the limitation and noises for future development. By integrating emergent computational technologies, this research delivers an accessible, scalable urban analytics platform that bridges the longstanding data gap between vertical surface materials and predictive thermal simulation.

146

ALGORITHMIC COOLING


07 C O N C L U S I O N

147


7.1 Discussion and Future Work

7.1.1 Energy Balance and Surrogate Model While our Radiant Load formulation establishes a methodological framework to describe outgoing radiative flux from vertical facades into the street canyon, we recognize that it does not directly capture cumulative pedestrian thermal exposure. To address this gap, we plan to incorporate pedestrian Mean Radiant Temperature (MRT) into our web platform, providing direct, actionable feedback aligned with outdoor thermal comfort benchmarks. Furthermore, although our current surrogate model successfully demonstrates proof of concept, its predictive precision across diverse material properties and surface colors remains constrained, primarily due to the limited number of initial training iterations. To expand, we need to train future iterations on broader material property spectra. In addition, the conclusions from our early experiments require clearer direction and additional validation, which we can address through focused experimentation and insights gained from grounded urban heat island, material property, and thermal comfort research. 7.1.2 Data Acquisition Pipeline: Data Source A primary limitation within our VLM process is data provenance. While our current raw image data provides wider coverage and consistent quality, our project can benefit from transitioning to open-source panorama sources. As an engineering trade-off, resolution and coverage may vary, requiring our data acquisition and post-processing pipelines to be adapted accordingly. 7.1.3 Data Post-Process Pipeline: Geometry Sorting A critical challenge encountered was the geometric matching from street images to OSM geometry. Image undistortion, ground pixel recognition, height adjustments, and mapping images to real-world coordinates each depend on accurate geometric sorting logic, where slight errors compound across steps. To address this, improved spatial sorting methods must be investigated, with refining GPS coordinate accuracy remaining the primary challenge to resolve.

148

ALGORITHMIC COOLING


7.1.4 Data Post-Process Pipeline: Duplicate Surfaces While the research pipeline successfully demonstrates regional material composition by sampling simulation results into unitized criteria, such as w/m², duplicate images still introduce spatial noise and uncertainty when evaluating the local causes and effects of thermal impacts. This can be addressed by implementing a logic to sort surfaces directly based on OSM geometry, rather than mapping each image independently onto the vector basemap. 7.1.5 Vision Language Model: Object and Material Recognision While our pipeline demonstrates the capability of using open-source models to recognize objects and materials, accuracy can be further improved by fine-tuning on domain-specific profiles and implementing higher-capacity models. 7.1.6 Data Acquisition and Post-Process Pipeline Although our current pipeline successfully scales single raw images into urban-scale, simulation-ready material masks, we anticipate that our workflow will be continuously updated and tailored to diverse design and planning applications as computer vision tools advance. 7.1.7 Analytic Portal Our portal is built using open-source libraries with a dedicated backend structure. The platform is scalable and adaptable to future system updates. With subsequent updates to our data and energy balance pipelines, the portal can be quickly adjusted for better performance and higher accuracy. Together, we anticipate improving overall accuracy, providing deeper insights into material properties, and bridging directly to decision-making tools already used in the design and planning industry.

07 C O N C L U S I O N

149


7.2 Conclusion

This dissertation set out to investigate the thermodynamic drivers of the Urban Heat Island (UHI) effect, specifically targeting the complex relationship between urban morphology, vertical surface materials, and microclimate behavior. By establishing a robust computational pipeline—from the precise extraction and rectification of street-level imagery using Inverse Perspective Mapping (IPM) to semantic material segmentation via Vision Language Models (Qwen-VL)—we have demonstrated a methodology for capturing the thermal realities of the urban canyon that traditional, top-down remote sensing often misses. The synthesis of this research culminates in the development of the Analytics Portal. This platform is not merely a repository of simulated data; it is designed as a scalable, interactive interface that translates complex thermodynamic relationships and surrogate model predictions into highly legible, user-centric visualizations. The portal successfully bridges the longstanding gap between abstract environmental data and actionable architectural design, allowing urban planners and architects to evaluate the thermal consequences of material choices at a pedestrian scale. Ultimately, by integrating emergent computational technologies, this research delivers an accessible urban analytics framework. It transforms isolated experimental observations into a structured, data-driven workflow, empowering decision-makers to implement evidence-based design strategies for mitigating the lethal escalation of urban heat.

150

ALGORITHMIC COOLING


07 C O N C L U S I O N

151


BIBLIOGRAPHY Acero, Juan A., and Ander Zozaya. “Cooling Singapore: Digital Urban Climate Twin (DUCT).” Presentation. Singapore-ETH Centre / Singapore-MIT Alliance for Research and Technology, 2020. Adams-Fuller, Terri. “Dangerous Discomfort.” Scientific American 329, no. 1 (July/August 2023): 64. https://doi.org/10.1038/scientificamerican0723-64. Apache Software Foundation. Apache ECharts. Version 5.x. Software library. Apache Software Foundation, 2024. https://echarts. apache.org/. Arnfield, A. J. “Two Decades of Urban Climate Research: A Review of Turbulence, Exchanges of Energy and Water, and the Urban Heat Island.” International Journal of Climatology 23, no. 1 (2003): 1–26. Arup. Urban Heat Snapshot: London’s Most Extreme Urban Heat Island “Hot Spot” Revealed in New Survey. London: Arup, 2024. Cabello, Ricardo, and Three.js Authors. Three.js. Version r169. Software library. GitHub repository, 2024. https://github.com/mrdoob/ three.js. Crawley, Drury B., et al. “EnergyPlus: Creating a New-Generation Building Energy Simulation Program.” Energy and Buildings 33, no. 4 (2001): 319–331. Del Campo, M. Neural Architecture: Design and Artificial Intelligence. Oro Editions, 2022. Gartland, Lisa. Heat Islands: Understanding and Mitigating Heat in Urban Areas. London: Earthscan, 2008. Google. “Street View Static API Documentation.” Google Maps Platform. Accessed June 2026. https://developers.google.com/maps/ documentation/streetview. Gorelick, Noel, Matt Hancher, Mike Dixon, Simon Ilyushchenko, David Thau, and Rebecca Moore. “Google Earth Engine: Planetary-Scale Geospatial Analysis for Everyone.” Remote Sensing of Environment 202 (2017): 18–27. https://doi.org/10.1016/j. rse.2017.06.031. Howard, Luke. The Climate of London: Deduced from Meteorological Observations Made at Different Places in the Neighbourhood of the Metropolis. 3 vols. London: Harvey and Darton, 1833. Infrared City. “Simulation Engine Basics.” Knowledge Base. September 23, 2025. Accessed July 14, 2026. https://infrared.city/knowledge-base/simulation-engine-basics/. MVRDV. “MVRDV Releases CarbonSpace for Free Public Use: A Transparent Tool to Help Reduce Embodied Carbon from Day One of the Design Process.” MVRDV, October 6, 2025. https://www.mvrdv.com/news/4767/mvrdv-releases-carbonspace-for-free-publicuse-a-transparent-tool-to-help-reduce-embodied-carbon-from-day-one-of-the-design-process. Kayanan, David R., Luis G. Resende Santos, Jordan Ivanchev, Jimeno A. Fonseca, and Leslie Norford. “Anthropogenic Heat Sources in Singapore.” Cooling Singapore Deliverable Technical Report D1.2.2.1. ETH Zurich Research Collection, 2019. Kilinc, Murat, et al. “Exploring the Urban Heat Island Effect: A Bibliometric and Topic Modeling Analysis.” Sustainability 17, no. 17 (2025): 8072. https://doi.org/10.3390/su17178072. Lawrie, Linda K., and Drury B. Crawley. “Development of Global Typical Meteorological Years (TMYx).” Climate.OneBuilding.Org, 2022. https://climate.onebuilding.org. Legeby, Ann, Daniel Koch, Fábio Duarte, et al. “New Urban Habits in Stockholm Following COVID-19.” Urban Studies 60, no. 8 (2023): 1448–1464. https://doi.org/10.1177/00420980211070677. MapLibre Contributors. MapLibre GL JS. Version 5.24.0. Software library. MapLibre, 2026. https://maplibre.org/. Met Office. “UK and Global Extreme Events – Heatwaves.” Accessed July 2026. https://www.metoffice.gov.uk/research/climate/understanding-climate/uk-and-global-extreme-events-heatwaves. Mughal, M. O., X.-X. Li, T. Yin, A. Martilli, O. Brousse, M. A. Dissegna, and L. K. Norford. “High-Resolution, Multilayer Modeling of Singapore’s Urban Climate Incorporating Local Climate Zones.” Journal of Geophysical Research: Atmospheres 124 (2019): 7764–7785.

152

ALGORITHMIC COOLING


MVRDV. “MVRDV Releases CarbonSpace for Free Public Use: A Transparent Tool to Help Reduce Embodied Carbon from Day One of the Design Process.” MVRDV, October 6, 2025. https://www.mvrdv.com/news/4767/mvrdv-releases-carbonspace-for-free-publicuse-a-transparent-tool-to-help-reduce-embodied-carbon-from-day-one-of-the-design-process. Ng, Y. X. Y. “A Study of Urban Heat Island Using ‘Local Climate Zones’: The Case of Singapore.” British Journal of Environment and Climate Change 5, no. 2 (2015): 116–133. Oke, T. R. “Street Canyon Microclimate.” Atmospheric Environment 22, no. 11 (1988): 2421–2423. OpenStreetMap Contributors. “Planet Dump.” OpenStreetMap Foundation. Accessed July 15, 2026. https://www.openstreetmap.org/. PostGIS Development Group. PostGIS: Spatial and Geographic Objects for PostgreSQL. Version 3.4. PostGIS, 2024. https://postgis. net/. PostgreSQL Global Development Group. PostgreSQL 16.0 Documentation. Software manual. PostgreSQL Global Development Group, 2024. https://www.postgresql.org/docs/. QGIS Development Team. QGIS Geographic Information System. Open Source Geospatial Foundation, 2024. https://www.qgis.org/. Ratti, C., N. Baker, and K. Steemers. “Energy Consumption and Urban Texture.” Energy and Buildings 37, no. 7 (2005): 762–776. Ratti, C., and A. Picon. The Atlas of the Senseable City. Yale University Press, 2023. Reçi, Dajana. “View of a Sunset over a City.” Photograph. Pexels, 2022. https://www.pexels.com/photo/view-of-a-sunset-over-acity-13207700/. Reinbigler, Marie, Romain Rouffet, Peter Naylor, Mikolaj Czerkawski, Nikolaos Dionelis, Elisabeth Brunet, Catalin Fetita, and Rosalie Martin. “HeatMat: Simulation of City Material Impact on Urban Heat Island Effect.” Computer Graphics Forum 45, no. 2 (2026). https:// doi.org/10.1111/cgf.70376. Reski, Nico, Carlo Navarra, Lotten Wiréhn, et al. “Urban Climate InteracTable: Towards an Immersive Contextual Data Analysis Platform to Visualize and Explore Urban Heat.” Virtual Reality 30, no. 1 (2026): article no. 7. https://doi.org/10.1007/s10055-025-01264-4. Romanello, Marina, Maria Walawender, Shih-Che Hsu, Annalyse Moskeland, Yasna Palmeiro-Silva, Daniel Scamman, James W. Smallcombe, et al. “The 2025 Report of the Lancet Countdown on Health and Climate Change: Climate Change Action Offers a Lifeline.” The Lancet 406, no. 10521 (2025): 2804. https://doi.org/10.1016/S0140-6736(25)01919-1. Ruefenacht, Lea A., and Juan Angel Acero, eds. Strategies for Cooling Singapore: A Catalogue of 80+ Measures to Mitigate Urban Heat Island and Improve Outdoor Thermal Comfort. Singapore-ETH Centre, 2017. Stewart, Iain D. “A Systematic Review and Scientific Critique of Methodology in Modern Urban Heat Island Literature.” International Journal of Climatology 31, no. 2 (2011): 200–217. Stewart, Iain D., and Tim R. Oke. “Local Climate Zones for Urban Temperature Studies.” Bulletin of the American Meteorological Society 93, no. 12 (2012): 1879–1900. Tabatabaei, Soha S., and Rima Fayaz. “The Effect of Facade Materials and Coatings on Urban Heat Island Mitigation and Outdoor Thermal Comfort in Hot Semi-Arid Climate.” Building and Environment 243 (2023): 110701. Tarkhan, Nada, Mikita Klimenka, Kelly Fang, Fabio Duarte, Carlo Ratti, and Christoph Reinhart. “Mapping Facade Materials Utilizing Zero-Shot Segmentation for Applications in Urban Microclimate Research.” Scientific Reports 15 (2025): 5492. https://doi.org/10.1038/ s41598-025-86307-1. Taylor, Jonathon, Paul Wilkinson, Mike Davies, Ben Armstrong, Zaid Chalabi, Anna Mavrogianni, Phil Symonds, Eleni Oikonomou, and Sylvia I. Bohnenstengel. “Mapping the Effects of Urban Heat Island, Housing, and Age on Excess Heat-Related Mortality in London.” Urban Climate 14 (2015): 517–528. United Nations Human Settlements Programme (UN-Habitat). World Cities Report 2022: Envisaging the Future of Cities. Nairobi: UNHabitat, 2022. U.S. Geological Survey (USGS). “Landsat 8 Collection 2 Tier 1 Level 2 Science Products.” Accessed July 6, 2026. https://earthexplorer.usgs.gov/. Voogt, J. A., and T. R. Oke. “Thermal Remote Sensing of Urban Climates.” Remote Sensing of Environment 86, no. 3 (2003): 370–384. Yoo, Wonjae, Mark J. Clayton, and Wei Yan. “ESMUST: EnergyPlus-Driven Surrogate Model for Urban Surface Temperature Prediction.” Building and Environment 229 (2023): 109935. https://doi.org/10.1016/j.buildenv.2022.109935.

BIBLIOGRAPHY

153


APPENDIX


155


APPENDIX Appendix 01 : London-Informed Material Database

London-Informed Material Database

Complete façade-material parameter set | 42 populated records | Thermal, solar and physical properties used in the surrogate-model workflow Thermal Absorptance

Solar Absorptance

Thickness (m)

Conductivity (W/mK)

Density (kg/m3)

Specific Heat (J/kgK)

Wall_Brick_Original

0.1025

0.48

1,513

800

Rough

0.93

0.7

0.3

Wall_Brick_Lighter

0.1025

0.48

1,513

800

Rough

0.93

0.55

0.45

Darker

Wall_Brick_Darker

0.1025

0.48

1,513

800

Rough

0.93

0.85

0.15

Original

Wall_Aluminium_Original

0.003

160

2,800

880

Smooth

0.2

0.4

0.6

Aluminium

Lighter

Wall_Aluminium_Lighter

0.003

160

2,800

880

Smooth

0.2

0.25

0.75

Wall

Aluminium

Darker

Wall_Aluminium_Darker

0.003

160

2,800

880

Smooth

0.2

0.6

0.4

7

Wall

Concrete

Original

Wall_Concrete_Original

0.15

1.65

2,200

1,000

MediumRough

0.9

0.65

0.35

8

Wall

Concrete

Lighter

Wall_Concrete_Lighter

0.15

1.65

2,200

1,000

MediumRough

0.9

0.45

0.55

9

Wall

Concrete

Darker

Wall_Concrete_Darker

0.15

1.65

2,200

1,000

MediumRough

0.9

0.8

0.2

10

Wall

Steel

Original

Wall_Steel_Original

0.005

54

7,833

465

Smooth

0.28

0.7

0.3

11

Wall

Steel

Lighter

Wall_Steel_Lighter

0.005

54

7,833

465

Smooth

0.28

0.45

0.55

12

Wall

Steel

Darker

Wall_Steel_Darker

0.005

54

7,833

465

Smooth

0.28

0.9

0.1

13

Wall

Glass

Original

Wall_Glass_Original

0.006

1

2,500

840

VerySmooth

0.84

0.15

0.85

14

Wall

Glass

Lighter

Wall_Glass_Lighter

0.006

1

2,500

840

VerySmooth

0.84

0.1

0.9

15

Wall

Glass

Darker

Wall_Glass_Darker

0.006

1

2,500

840

VerySmooth

0.84

0.5

0.5

16

Wall

Wood (Douglas Fir)

Original

Wall_WoodDouglasFir_Original

0.025

0.14

510

1,600

MediumSmooth

0.9

0.6

0.4

17

Wall

Wood (Douglas Fir)

Lighter

Wall_WoodDouglasFir_Lighter

0.025

0.14

510

1,600

MediumSmooth

0.9

0.35

0.65

18

Wall

Wood (Douglas Fir)

Darker

Wall_WoodDouglasFir_Darker

0.025

0.14

510

1,600

MediumSmooth

0.9

0.85

0.15

19

Wall

Terracotta

Original

Wall_Terracotta_Original

0.02

0.81

1,700

840

Rough

0.9

0.7

0.3

20

Wall

Terracotta

Lighter

Wall_Terracotta_Lighter

0.02

0.81

1,700

840

Rough

0.9

0.55

0.45

21

Wall

Terracotta

Darker

Wall_Terracotta_Darker

0.02

0.81

1,700

840

Rough

0.9

0.85

0.15

22

Wall

Limestone

Original

Wall_Limestone_Original

0.05

1.4

2,000

1,000

MediumRough

0.9

0.55

0.45

23

Wall

Limestone

Lighter

Wall_Limestone_Lighter

0.05

1.4

2,000

1,000

MediumRough

0.9

0.4

0.6

24

Wall

Limestone

Darker

Wall_Limestone_Darker

0.05

1.4

2,000

1,000

MediumRough

0.9

0.7

0.3

25

Wall

Stone (Granite)

Original

Wall_StoneGranite_Original

0.05

2.8

2,600

1,000

Rough

0.9

0.65

0.35

26

Wall

Stone (Granite)

Lighter

Wall_StoneGranite_Lighter

0.05

2.8

2,600

1,000

Rough

0.9

0.45

0.55

27

Wall

Stone (Granite)

Darker

Wall_StoneGranite_Darker

0.05

2.8

2,600

1,000

Rough

0.9

0.8

0.2

28

Wall

Cement/Mortar

Original

Wall_CementMortar_Original

0.02

0.79

1,920

1,000

VeryRough

0.9

0.65

0.35

29

Wall

Cement/Mortar

Lighter

Wall_CementMortar_Lighter

0.02

0.79

1,920

1,000

VeryRough

0.9

0.45

0.55

30

Wall

Cement/Mortar

Darker

Wall_CementMortar_Darker

0.02

0.79

1,920

1,000

VeryRough

0.9

0.8

0.2

31

Wall

Asphalt

Original

Wall_Asphalt_Original

0.02

0.7

2,100

1,000

Rough

0.93

0.9

0.1

32

Wall

Asphalt

Lighter

Wall_Asphalt_Lighter

0.02

0.7

2,100

1,000

Rough

0.93

0.7

0.3

33

Wall

Asphalt

Darker

Wall_Asphalt_Darker

0.02

0.7

2,100

1,000

Rough

0.93

0.95

0.05

34

Wall

Slate

Original

Wall_Slate_Original

0.006

2.2

2,400

1,000

MediumRough

0.9

0.85

0.15

35

Wall

Slate

Lighter

Wall_Slate_Lighter

0.006

2.2

2,400

1,000

MediumRough

0.9

0.65

0.35

36

Wall

Plaster

Original

Wall_Plaster_Render

0.02

0.4

1,850

840

MediumRough

0.35

0.2

0.8

37

Wall

Slate

Darker

Wall_Slate_Darker

0.006

2.2

2,400

1,000

MediumRough

0.9

0.92

0.08

38

Roof

Concrete Tile

Original

Roof_ConcreteTile_Original

0.02

1.65

2,200

1,000

MediumRough

0.9

0.7

0.3

39

Roof

Concrete Tile

Lighter

Roof_ConcreteTile_Lighter

0.02

1.65

2,200

1,000

MediumRough

0.9

0.5

0.5

40

Roof

Concrete Tile

Darker

Roof_ConcreteTile_Darker

0.02

1.65

2,200

1,000

MediumRough

0.9

0.85

0.15

41

MINIMUM

0.003

0.14

510

465

0

0.2

0.1

0.9

42

MAXIMUM

0.15

160

7833

1600

0

0.93

0.95

0.05

ID

Category

Material

Variant

1

Wall

Brick

Original

2

Wall

Brick

Lighter

3

Wall

Brick

4

Wall

Aluminium

5

Wall

6

Honeybee Material Name

Roughness

Note: Values and source descriptions are reproduced from the supplied material database. O = Original, L = Lighter, and G = Darker material-colour variants.

156

ALGORITHMIC COOLING

Solar Reflectance

A


ce

Solar Absorptance

Solar Reflectance

Visible Absorptance

Thermal Capacity (J/m3 K)

Emissivity

Data Source

0.7

0.3

0.7

12,10,400

0.93

CIBSE Guide A / BS EN ISO 10456:2007 (EN ISO 12524:2000) 'Brick'; ASHRAE Ch.26 cross-checked (range 0.4-0.8 W/mK for common brick, consistent)

0.55

0.45

0.55

12,10,400

0.93

CIBSE Guide A / EN ISO 12524:2000 'Brick'; ASHRAE Ch.26 colour banding

0.85

0.15

0.85

12,10,400

0.93

CIBSE Guide A / EN ISO 12524:2000 'Brick'; ASHRAE Ch.26 colour banding

0.4

0.6

0.4

24,64,000

0.2

CIBSE Guide A / EN ISO 12524:2000 'Aluminium'; matches ASHRAE Ch.26 metals table exactly (k=160 W/mK, rho=2800 kg/m3, c=880 J/kgK)

0.25

0.75

0.25

24,64,000

0.2

CIBSE Guide A / EN ISO 12524:2000 'Aluminium'; ASHRAE Ch.26 colour banding

0.6

0.4

0.6

24,64,000

0.2

CIBSE Guide A / EN ISO 12524:2000 'Aluminium'; ASHRAE Ch.26 colour banding

0.65

0.35

0.65

22,00,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Medium concrete'; ASHRAE Ch.26 medium-density concrete range 1.3-1.8 W/mK, consistent

0.45

0.55

0.45

22,00,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Medium concrete'; ASHRAE Ch.26 colour banding

0.8

0.2

0.8

22,00,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Medium concrete'; ASHRAE Ch.26 colour banding

0.7

0.3

0.7

36,42,345

0.28

ASHRAE Ch.26 metals table / EngineeringToolbox 'Carbon steel (AISI 1050)'; emissivity corrected 0.9->0.28 to match bare/mill-finish steel per ASHRAE Ch.26 (0.20-0.32), not a painted-surface default

0.45

0.55

0.45

36,42,345

0.28

ASHRAE Ch.26 / EngineeringToolbox 'Carbon steel'; colour banding

0.9

0.1

0.9

36,42,345

0.28

ASHRAE Ch.26 / EngineeringToolbox 'Carbon steel'; colour banding

0.15

0.85

0.1

21,00,000

0.84

CIBSE Guide A / EN ISO 12524:2000 'Glass'; matches ASHRAE Ch.26 glazing properties table

0.1

0.9

0.06

21,00,000

0.84

CIBSE Guide A / EN ISO 12524:2000 'Glass'; ASHRAE Ch.26 colour banding (clear/light tint)

0.5

0.5

0.5

21,00,000

0.84

CIBSE Guide A / EN ISO 12524:2000 'Glass'; ASHRAE Ch.26 colour banding (tinted)

0.6

0.4

0.7

8,16,000

0.9

USDA Forest Products Laboratory, Wood Handbook (Douglas-fir, 12% MC); ASHRAE Ch.26 wood conductivity range 0.10-0.16 W/mK, consistent

0.35

0.65

0.55

8,16,000

0.9

USDA FPL Wood Handbook; ASHRAE Ch.26 colour banding

0.85

0.15

0.85

8,16,000

0.9

USDA FPL Wood Handbook; ASHRAE Ch.26 colour banding

0.7

0.3

0.7

14,28,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Terracotta'; ASHRAE Ch.26 fired-clay products range 0.6-1.0 W/mK, consistent

0.55

0.45

0.55

14,28,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Terracotta'; ASHRAE Ch.26 colour banding

0.85

0.15

0.85

14,28,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Terracotta'; ASHRAE Ch.26 colour banding

0.55

0.45

0.55

20,00,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Semi-hard limestone'; ASHRAE Ch.26 limestone range 1.3-1.7 W/mK, consistent

0.4

0.6

0.4

20,00,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Limestone'; ASHRAE Ch.26 colour banding

0.7

0.3

0.7

20,00,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Limestone'; ASHRAE Ch.26 colour banding

0.65

0.35

0.65

26,00,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Granite'; ASHRAE Ch.26 dense natural stone range 2.5-3.5 W/mK, consistent

0.45

0.55

0.45

26,00,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Granite'; ASHRAE Ch.26 colour banding

0.8

0.2

0.8

26,00,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Granite'; ASHRAE Ch.26 colour banding

0.65

0.35

0.65

19,20,000

0.9

Demirboga (2003), Build.&Environ. (k,rho); c per CIBSE Guide A typical mortar; ASHRAE Ch.26 mortar/render range 0.7-0.9 W/mK, consistent

0.45

0.55

0.45

19,20,000

0.9

Demirboga (2003) + CIBSE Guide A; ASHRAE Ch.26 colour banding

0.8

0.2

0.8

19,20,000

0.9

Demirboga (2003) + CIBSE Guide A; ASHRAE Ch.26 colour banding

0.9

0.1

0.9

21,00,000

0.93

ASHRAE Ch.26 / CIBSE Guide A typical asphalt/paving design value (0.6-0.75 W/mK), consistent

0.7

0.3

0.7

21,00,000

0.93

ASHRAE Ch.26 / CIBSE Guide A asphalt; colour banding

0.95

0.05

0.95

21,00,000

0.93

ASHRAE Ch.26 / CIBSE Guide A asphalt; colour banding

0.85

0.15

0.85

24,00,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Slate'; ASHRAE Ch.26 dense stone/slate range 2.0-2.7 W/mK, consistent

0.65

0.35

0.65

24,00,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Slate'; ASHRAE Ch.26 colour banding

0.2

0.8

0.3

15,54,000

0.9

0.92

0.08

0.92

24,00,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Slate'; ASHRAE Ch.26 colour banding

0.7

0.3

0.7

22,00,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Medium concrete'; ASHRAE Ch.26 cross-checked

0.5

0.5

0.5

22,00,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Medium concrete'; ASHRAE Ch.26 colour banding

0.85

0.15

0.85

22,00,000

0.9

CIBSE Guide A / EN ISO 12524:2000 'Medium concrete'; ASHRAE Ch.26 colour banding

0.1

0.9

0.06

816000

0.2

0.95

0.05

0.95

3642345

0.93

APPENDIX

157


Appendix 02.1 : Street-Level Sphere Acquisition (Scripts 1 & 2) To populate the pipeline without storing imagery on a personal machine, Script 1 reads the single RUNNING row of control_panel.xlsx, looks up that tile in gis_tiles.csv, and samples camera stations along OpenStreetMap street centrelines. For every surviving point the Street View metadata API resolves the nearest official Google panorama (user-contributed spheres are rejected). Rather than the Static API’s rectilinear crops, which slice facades and roofs, the script fetches the Zoom-3 equirectangular tile grid and sews a true 4096×2048 sphere. Heading is recorded as 0.0 at this stage: Script 2 then patches each record with the sensor-measured heading, tilt and roll from the Maps Tile API, a field the Static metadata endpoint has never returned.

# 1_download_spheres.py — OSM network + tile pad

# 1_download_spheres.py — official pano + stitch

# URBAN MATERIAL PIPELINE — Script 1: acquire spheres

# Keep only official Google imagery. User spheres

# CRS: WGS84 in, British National Grid for metric maths

# (e.g. “© John Doe”) are rejected for consistency.

CRS_GEOGRAPHIC: str = “EPSG:4326”

if “Google” not in str(data.get(“copyright”, “”)):

CRS_METRIC: str = “EPSG:27700” def download_drive_network(bounds: TileBounds):

return None # Zoom 3 = 8×4 grid of 512 px tiles → 4096×2048 sphere

# Query a padded box so streets that cross the

PANO_ZOOM, PANO_GRID_COLS, PANO_GRID_ROWS = 3, 8, 4

# tile edge are captured whole; overspill is

PANO_OUTPUT_SIZE = (4096, 2048)

# clipped after sampling. bbox = _osmnx_bbox(bounds.buffered(BBOX_BUFFER_DEG)) return ox.graph_from_bbox(

def download_panorama(session, pano_id: str, out_path: Path): # Incremental: reuse a sphere already on disk

bbox=bbox,

cached = _existing_panorama(pano_id)

network_type=”all”,

if cached is not None:

custom_filter=OSM_CUSTOM_FILTER, )

return cached canvas = Image.new(“RGB”, PANO_OUTPUT_SIZE) for x in range(PANO_GRID_COLS):

# 1_download_spheres.py — sample + building filter

for y in range(PANO_GRID_ROWS):

# Place a camera every Sampling_Distance_m along

tile = _fetch_tile(session, pano_id, x, y)

# street centrelines, then keep only points near a

canvas.paste(tile, (x * 512, y * 512))

# building (parks / open land are discarded).

canvas.save(out_path, format=”JPEG”, quality=95)

def sample_points_along_network(graph, spacing_m: float):

return out_path

graph_proj = ox.project_graph(graph, to_crs=CRS_METRIC) edges = ox.graph_to_gdfs(graph_proj, nodes=False, edges=True)

# 2_patch_headings.py — Tile API sensor pose

points: List[Point] = []

# The Static metadata API never returns heading.

for geom in edges.geometry.values:

# Maps Tile API streetview/metadata does: heading,

n_steps = int(math.floor(geom.length / spacing_m))

# tilt, roll — the same numbers the JS API exposes

for i in range(n_steps + 1):

class TileApiClient:

points.append(geom.interpolate(i * spacing_m)) return gpd.GeoDataFrame(geometry=points, crs=CRS_METRIC)

def fetch_orientation(self, pano_id: str): self._ensure_session() resp = self.http.get( f”{TILE_API_BASE}/streetview/metadata”,

def filter_points_near_buildings(

params={“session”: self._session_token,

points_metric, buildings, radius_m: float,

“key”: self.api_key, “panoId”: pano_id},

): buffered = points_metric.copy()

)

buffered[“geometry”] = points_metric.geometry.buffer(radius_m)

data = resp.json()

joined = gpd.sjoin(

heading = data.get(“heading”)

buffered, buildings.to_crs(CRS_METRIC), how=”inner”, predicate=”intersects”, ) return points_metric.loc[joined.index.unique()]

if heading is None: return None, None, None return (float(heading) % 360.0, float(data.get(“tilt”) or 0.0), float(data.get(“roll”) or 0.0))

158

ALGORITHMIC COOLING


Appendix 02.2 : Facade Geometry & Gnomonic Render (Script 3) Script 3 is the pipeline’s geometrical brain. First it explodes every OSM building ring into one macro-facade per physical street frontage, micro-fusion of noisy edges, primary-street assignment, a ring-walk that absorbs short perpendicular return walls, then wall-only anchoring so the reported line sits on the outermost face. For each sphere station it independently aims a virtual camera at the left and right sidewalks. The yaw is the exact inverse of that wall’s outward normal. A side with no valid candidate falls back to a plain orthogonal heading; both sidewalks are always rendered. The sphere is levelled (undoing sensor tilt/roll) before it is aimed and pitched, then projected gnomonic into a tall portrait crop.

# 3_extract_facades.py — per-street absorbed grouping

# If left and right yaws end up within 90°, force

# One macro-facade per physical STREET FRONTAGE,

# BOTH back to plain orthogonal — plaza duplicates.

# not a fixed 8-way cardinal bin.

if angle_diff < DUPLICATE_GUARD_MAX_ANGLE_DIFF_DEG:

def _explode_polygon_to_walls(geom, osm_id, street_index): ring_lines = _build_ring_lines(list(geom.exterior.coords))

yaw_left

= _wrap360(fallback_ref_deg - 90.0)

yaw_right = _wrap360(fallback_ref_deg + 90.0)

ring_lines = _detect_and_fuse_curve_chains(ring_lines) primary = assign_primary_streets(ring_lines, street_index)

# One centre-ray. OSM polygon first (physical wall);

raw = approach3_absorbed_groups_for_building(ring_lines, primary)

# exploded FacadeWall only if the polygon ray misses.

raw = _merge_continuous_same_street(raw, ring_lines)

az = math.radians(camera_yaw) ray = LineString([(cam_x, cam_y),

for street_name, members_idx in raw: g = _finalize_group(members_idx, ring_lines, street_name, street_index) # Normal = mean of dominant (>= 4 m) runs only.

(cam_x + math.sin(az) * radius_m, cam_y + math.cos(az) * radius_m)]) building_hit = _nearest_ray_hit_xy( origin, ray, building_tree, building_geoms)

# Origin = longest run closest to the street —

chosen = building_hit or facade_hit

# never a centroid blended across setbacks.

hx, hy, ray_dist = chosen

cardinal = _azimuth_to_cardinal(g.normal_az_deg) facade_id = f”{osm_id}_{cardinal}”

# Signed offset onto the street normal nearer yaw

walls.append(FacadeWall(

# = the projection-plane distance, not ray length.

line=LineString([g.start_xy, g.end_xy]),

n_deg = _street_normal_look_deg(camera_yaw, street_tangent_deg)

facade_id=facade_id, length_m=g.total_length,

nx, ny = math.sin(math.radians(n_deg)), math.cos(math.radians(n_deg))

normal_az_deg=g.normal_az_deg,

depth = (hx - cam_x) * nx + (hy - cam_y) * ny

faces_street=True, street_name=g.street_name,

return PlaneMeasurement(depth_m=depth, hit_xy=(hx, hy),

))

source=”osm_polygon”)

# 3_extract_facades.py — facade-centric aiming

# 3_extract_facades.py — LEVEL then AIM then PITCH

# Strict sectors: dead-ahead / dead-behind = dead zone

def render_gnomonic(pano, yaw_deg, pitch_deg, fov_deg,

LEFT_SECTOR

= (-120.0, -30.0)

RIGHT_SECTOR = (

30.0, 120.0)

out_w, out_h, base_tilt_deg, base_roll_deg): # Stage A — LEVEL: undo the sphere’s own tilt/roll # FIRST, before any look direction is applied

# Yaw = exact inverse of the Primary Facade normal for side in (“left”, “right”): primary = find_primary_facade( station.x, station.y, by_side[side], street_ref_deg) if primary is not None and primary[1] <= 45.0:

# Stage B — AIM: yaw about the leveled frame’s OWN up r_yaw = _rotation_about_axis(up_lvl, math.radians(-yaw_deg)) fwd_yaw = r_yaw @ fwd_lvl right_yaw = r_yaw @ right_lvl

wall, parallel_delta, dist = primary yaw = _wrap360(wall.normal_az_deg + 180.0) else:

# Stage C — PITCH: look up about the aimed right axis r_pitch = _rotation_about_axis(right_yaw, math.radians(pitch_deg))

# No candidate, or too skewed (junction): # never borrow the other sidewalk. yaw = _wrap360(fallback_ref_deg - 90.0) if side == “left” \ else _wrap360(fallback_ref_deg + 90.0)

rays = cam_vecs @ np.stack( [right_yaw, r_pitch @ up_lvl, r_pitch @ fwd_yaw], 1).T azimuth = np.arctan2(rays[..., 0], rays[..., 1]) elevation = np.arcsin(np.clip(rays[..., 2], -1, 1)) return _bilinear_sample(pano, u, v)

APPENDIX

159


Appendix 02.3 : Full-Frame Street-Front IPM (Script 4) Script 4 orthorectifies each Script 3 crop as one complete street-front image: every facade visible in the frame stays in the frame; nothing is sliced by OSM wall length. It places a street-parallel vertical plane at Script 3’s already-measured plane_depth_m and does not re-cast depth. Inverse mapping via cv2.remap samples the source photograph at every metric canvas pixel, locking both axes at 30 px/m. The saved Z-band is always street level to 25 m (750 px), independent of depth, FOV or wall height, so every frame is a commensurate metric ruler for later overlap.

# 4_masking_fullframe.py — metric lock (never measured)

# 4_masking_fullframe.py — street-parallel plane

# URBAN MATERIAL PIPELINE — Script 4b: street-front IPM

def place_plane_from_script3(

# Horizontal and vertical scale are FIXED. A plane

cam_x, cam_y, camera_yaw, fov_deg,

# rotated away from camera_yaw changes WHICH source

street_tangent_deg, depth_m,

# pixels are read — never how many metres a

):

# destination pixel represents.

# Normal = whichever of tangent +- 90 is nearer yaw.

CAMERA_HEIGHT_M: float = 2.5

# Width = the crop FOV chord on that plane, clamped. cand_a = _wrap360(street_tangent_deg - 90.0)

WALL_BOTTOM_HEIGHT_M: float = -2.5 WALL_TOP_HEIGHT_M: float = 35.0

# warp canvas = 1125 px

cand_b = _wrap360(street_tangent_deg + 90.0)

FIXED_TOP_HEIGHT_M: float = 25.0

# saved Z-band = 750 px

n_bearing = cand_a if abs(_wrap180(camera_yaw - cand_a)) \

PIXELS_PER_METER: float = 30.0

<= abs(_wrap180(camera_yaw - cand_b)) else cand_b nx, ny = _bearing_vec(n_bearing)

MIN_DEPTH_M: float = 3.5

tux, tuy = _bearing_vec(_wrap360(n_bearing + 90.0))

MAX_STREET_FRONT_DEPTH_M: float = 30.0 # Bound phi so u = D * tan(phi) cannot run to infinity

u_min = depth_m * math.tan(math.radians(phi_left))

MAX_OBLIQUITY_DEG: float = 60.0

u_max = depth_m * math.tan(math.radians(phi_right))

MAX_PLANE_WIDTH_M: float = 80.0

cx = cam_x + depth_m * nx cy = cam_y + depth_m * ny

# 4_masking_fullframe.py — street-parallel plane

start_xy = (cx + u_min * tux, cy + u_min * tuy)

def place_plane_from_script3(

end_xy

cam_x, cam_y, camera_yaw, fov_deg,

= (cx + u_max * tux, cy + u_max * tuy)

return PlaneSolution(start_xy, end_xy, depth_m, width_m)

street_tangent_deg, depth_m, ):

# 4_masking_fullframe.py — identical Z-band every frame # Normal = whichever of tangent +- 90 is nearer yaw.

def crop_to_height_band(warped):

# Width = the crop FOV chord on that plane, clamped.

# Z = 0 .. 25 m at the global 30 px/m lock —

cand_a = _wrap360(street_tangent_deg - 90.0)

# always 750 px tall, for every frame.

cand_b = _wrap360(street_tangent_deg + 90.0)

crop_height_px = int(round(FIXED_TOP_HEIGHT_M * PIXELS_PER_METER))

n_bearing = cand_a if abs(_wrap180(camera_yaw - cand_a)) \

row_ground = wall_z_to_canvas_row(0.0, warped.shape[0])

<= abs(_wrap180(camera_yaw - cand_b)) else cand_b

return warped[row_ground + 1 - crop_height_px:row_ground + 1]

nx, ny = _bearing_vec(n_bearing) tux, tuy = _bearing_vec(_wrap360(n_bearing + 90.0))

# Failures go to flagged/, never silently emitted if width_px < MIN_OUTPUT_WIDTH_PX:

u_min = depth_m * math.tan(math.radians(phi_left))

reasons.append(f”narrow_output({width_px}px)”)

u_max = depth_m * math.tan(math.radians(phi_right))

quality = “failed” if reasons else “ok”

cx = cam_x + depth_m * nx

out_dir = FLAGGED_DIR if quality == “failed” else OUTPUT_DIR

cy = cam_y + depth_m * ny

cv2.imwrite(str(out_dir / f”{stem}.jpg”), band)

start_xy = (cx + u_min * tux, cy + u_min * tuy) end_xy

= (cx + u_max * tux, cy + u_max * tuy)

return PlaneSolution(start_xy, end_xy, depth_m, width_m)

160

# Registry consumed by Script 5 overlap: # start_xy, end_xy, length_m, depth_m, px_per_meter

ALGORITHMIC COOLING


Appendix 02.4 : ComfyUI Classification Graph (Sky, Gate, Materials) After Script 4, each street-front JPEG is posted to a ComfyUI graph on the project VM. The graph does not rewrite geometry: it decides which pixels are wall, whether the frame is usable, and which material those wall pixels are. Three groups run in sequence. SKY strips everything that is not facade. Grounding DINO + SAM2 answer two open-vocabulary prompts (“tree, vegetation” and “facade, building”); YOLOv8-seg adds COCO obstacles (person, car, truck, bus). Vegetation is inverted, unioned with the YOLO mask, and composited onto a blank canvas so only the building face remains. GATE is a hard AND. Qwen3-VL-2B must reply with the single word ACCEPT (rejecting interiors and scaffolding) and AC-Pixel Coverage must find at least 15 percent non-black facade (black threshold 0.06). If either fails, AC-Gate Halt drops the job before any material model is billed. MATERIALS asks GPT-4.1-mini for an unconstrained architectural caption, splits it on “#”, and feeds ByteDance Sa2VA-Qwen3-VL-4B seven material heads (glass, concrete, stone, brick, plaster, wood, metal). Per-class thresholds turn soft maps into binary masks (glass 0.50, wood 0.80, metal 0.50, the rest 0.20); speckle below 32 px is discarded. Masks are written back to SQL for the map.1

1 ComfyUI pipeline on the next page

APPENDIX

161


OBSTRUCTION

GATE

162

ALGORITHMIC COOLING


MATERIALS

APPENDIX

163


Appendix 03 : Backend API (Flask) To enable scalability for the web platform, the backend API was structured to receive HTTPS requests from web browsers (clients). This allows data to be managed and updated in an SQL database hosted on an Oracle Virtual Machine (VM), without having to manage data on a personal device. The API service also serves the data acquisition and post-processing pipelines, where results from each pipeline are also stored in the SQL database. Below is the two selected API service from 16 services in different research phase, #14 Post Facade Materials updates metadata after each task in ComfyUI, and #16 Get Facade Materials from database to the client browser :

# ============================================================ # MATERIAL CLASSIFICATION PIPELINE — write & read # ============================================================ from flask import Flask, request, jsonify import psycopg2 from psycopg2.extras import RealDictCursor, Json from flask_cors import CORS import os from pathlib import Path from dotenv import load_dotenv load_dotenv(Path(__file__).resolve().parent / “.env”) app = Flask(__name__) # Only the frontend-facing GET route needs CORS; the POST route # below is called server-side by the classifier, not a browser. CORS(app, resources={ r”/06_facade_materials”: {“origins”: [ “https://algorithmiccooling.com”, “http://localhost:5173”, ]}, }) DB_CONFIG = { “host”: os.environ[“DB_HOST”], “dbname”: os.environ[“DB_NAME”], “user”: os.environ[“DB_USER”], “password”: os.environ[“DB_PASSWORD”], } API_SECRET = os.environ[“API_SECRET”] def get_db_connection(): return psycopg2.connect(**DB_CONFIG) def check_auth(req_data): return req_data.get(‘secret’) == API_SECRET

164

# ============================================================ # #14 upload_06_facade_materials :: Client = ComfyUI custom node # # WRITE PATH — save a classification result # # Goal: persist one classifier pass against the facade crop it ran on. # # The classifier posts a status, the two output image URLs (the # original crop and its colour-coded segmentation mask), and a # metadata blob describing the material breakdown. The blob is # flattened into per-material columns so the table stays queryable # without JSON parsing downstream. # ============================================================ MATERIAL_CATEGORIES = (“glass”,) repeats this per material

# one category shown; the real table

def _flatten_materials(meta): “””metadata[‘materials’] -> {“glass”: (percent, tone), ...}.””” out = {c: (None, None) for c in MATERIAL_CATEGORIES} # None = not measured, 0.0 = measured as absent if not isinstance(meta, dict): return out for m in meta.get(‘materials’) or []: cat = str(m.get(‘category’, ‘’)).strip().lower() if cat in out: out[cat] = (float(m.get(‘percentage’, 0.0)), float(m. get(‘tone’, 0.0))) return out @app.route(‘/upload_06_facade_materials’, methods=[‘POST’]) def upload_06_facade_materials(): data = request.json if not check_auth(data): return jsonify({“error”: “Unauthorized”}), 401 meta = data.get(‘metadata’) mats = _flatten_materials(meta)

ALGORITHMIC COOLING


params = { ‘status’: data[‘status’], ‘image_url’: data.get(‘image_url’), ‘segmented_image_url’: data.get(‘segmented_image_url’), ‘is_valid’: data.get(‘is_valid’), ‘metadata’: Json(meta) if meta is not None else None, ‘job_id’: data[‘job_id’], } for cat, (pct, tone) in mats.items(): params[f’mat_{cat}_pct’] = pct params[f’mat_{cat}_tone’] = tone conn = get_db_connection() cur = conn.cursor() # overwrite, not merge: each POST is a full report of one classification attempt cur.execute(‘’’ UPDATE “06_facade_materials” SET status = %(status)s, image_url = %(image_url)s, segmented_image_url = %(segmented_image_url)s, is_valid = %(is_valid)s, metadata = %(metadata)s, mat_glass_pct = %(mat_glass_pct)s, mat_glass_tone = %(mat_glass_tone)s, finished_at = now() WHERE id = %(job_id)s; ‘’’, params) conn.commit() cur.close() conn.close() return jsonify({“status”: “success”, “job_id”: data[‘job_id’]}), 200 # ============================================================ # #16 get_06_facade_materials :: Client = frontend portal # # READ PATH — fetch material crops + masks for the frontend # # Goal: give the portal everything it needs to drape a classification # result onto the facade it belongs to. # # Joins the classification result back to the facade’s photographed

APPENDIX

# crop, reprojecting the wall’s endpoints from the local survey grid # (EPSG:27700) to WGS84 for the map. Only passed, validated results # are returned. # ============================================================ @app.route(‘/06_facade_materials’, methods=[‘GET’]) def get_06_facade_materials(): conn = get_db_connection() cur = conn.cursor(cursor_factory=RealDictCursor) cur.execute(‘’’ WITH src AS ( SELECT m.image_url AS material_crop_url, m.segmented_image_url AS material_mask_url, sf.facade_id, sf.station_id, sf.side, sf.top_height_m, sf.bottom_height_m, ST_Transform(ST_SetSRID(ST_MakePoint( (sf.start_xy->>0)::float8,(sf.start_xy>>1)::float8),27700),4326) AS start_pt, ST_Transform(ST_SetSRID(ST_MakePoint( (sf.end_xy->>0)::float8,(sf.end_xy>>1)::float8),27700),4326) AS end_pt FROM “06_facade_materials” m JOIN “04_street_fronts” sf ON sf.id = m.source_row_id WHERE m.status = ‘PASSED’ AND m.is_valid IS TRUE AND m.segmented_image_url IS NOT NULL ) SELECT facade_id, station_id, side, material_crop_url, material_mask_url, ST_X(start_pt) AS start_lng, ST_Y(start_pt) AS start_lat, ST_X(end_pt) AS end_lng, ST_Y(end_pt) AS end_lat, bottom_height_m AS img_bottom_m, top_height_m AS img_top_m FROM src ORDER BY facade_id, station_id, side ‘’’) rows = cur.fetchall() cur.close() conn.close() return jsonify(rows), 200

165


Appendix 04.1 : Facade-query.js 13 selected JS scripts are simplified and displayed in appendix, representing the core simulation and sampling modules. Facade-query.js loads every facade images and material masks by sending a site rectangle query. After acquiring image data, they are normalised and mapped into a line with building height.

// ============================================================ // SITE QUERY — loading the walls inside a selected site // // Source: js/workflow/facade-query.js // ============================================================ // ---- Parameters -------------------------------------------------// Two datasets can feed the pipeline. The material base is the one in // use: the surrogate requires material inputs, so a wall with no // classified mask cannot be simulated. const SIMULATION_BASES = { photo: { key: ‘photo’, endpointPath: ‘/06_facade_images’ }, material: { key: ‘material’, endpointPath: ‘/06_facade_materials’ }, };

bbox, cfg = FACADE_QUERY_CONFIG, base = SIMULATION_BASES.material, ) { const url = `${API_BASE}${base.endpointPath}?bbox=${bbox.join(‘,’)}`; const controller = new AbortController(); setTimeout(() => controller.abort(), cfg.requestTimeoutMs); const res = await fetch(url, { signal: controller.signal }); if (!res.ok) throw new Error(`HTTP ${res.status}`); const rows = await res.json(); return rows.map(normalizeMaterialRow).slice(0, cfg.maxFacades); }

const FACADE_QUERY_CONFIG = { requestTimeoutMs: 20000, // abort a stalled request maxFacades: 5000, // safety valve against a mis-typed bbox }; // ---- The shared facade shape ------------------------------------// Downstream modules read only start, end, normalAzDeg, imgBottomM // and imgTopM, so either dataset can feed one pipeline. function normalizeMaterialRow(row) { return { facadeId: row.facade_id, // The mask is what the wall shows by default. The crop is the // classifier’s own re-cut of the photograph, shown beside it for // comparison and fed to nothing. imageUrl: row.material_mask_url, maskUrl: row.material_mask_url, cropUrl: row.material_crop_url, start: [Number(row.start_lng), Number(row.start_lat)], end: [Number(row.end_lng), Number(row.end_lat)], normalAzDeg: Number(row.normal_az_deg), north

// clockwise from grid

// The orthophoto’s fixed camera window, not a building height. imgBottomM: Number(row.img_bottom_m), imgTopM: Number(row.img_top_m), }; } // ---- The request ------------------------------------------------// Throws on failure rather than falling back to local data. An // unreachable API must read as a failure, not as a site with fewer // walls. export async function queryFacades(

166

ALGORITHMIC COOLING


Appendix 04.2 : Facade-grid.js Facade-grid.js divides each wall into sampling cells of around two metres square, sized from the wall’s own length and height. Each cell carries one sky view factor, one material and one temperature, so this step sets the spatial resolution of every later result.

// ============================================================ // FACADE GRID — cutting a wall into sampling cells // // Source: js/lib/facade-grid.js // ============================================================ // ---- Parameters ----------------------------------------------// targetSizeM is a sampling interval, not the size of the smallest // modelled unit: a cell can contain pixels of several materials. Cell // count is a square law, and both the sky view factor scan and the // model pass are per cell. const FACADE_GRID_CONFIG = { targetSizeM: 2.0, // nominal cell edge, metres minCols: 2, maxCols: 24, // clamps: keep a sliver of wall from minRows: 4, maxRows: 48, // collapsing to a single cell };

// ---- The grid ---------------------------------------------------// The wall sits on the orthophoto’s camera window, not on the // building’s reported height. Most buildings have no measured height, // and cropping a real photograph to match an estimate discards // correct imagery. export function facadeGrid(facade, config = FACADE_GRID_CONFIG) { const baseM = facade.imgBottomM; const heightM = facade.imgTopM - facade.imgBottomM; const lengthM = facadeLengthM(facade); // null lets callers skip a wall rather than divide by zero. if (!(lengthM > 0) || !(heightM > 0)) return null; // Computed independently, each from one wall dimension, so a long // low wall gets wide short cells instead of forced square ones. const cols = clampInt(lengthM / config.targetSizeM, config.minCols, config.maxCols); const rows = clampInt(heightM / config.targetSizeM, config.minRows, config.maxRows);

// ---- Local metric frame --------------------------------------const M_PER_DEG_LNG_EQ = 111320; // Latitude-dependent, not a flat constant. The meridian degree grows // toward the poles, and an equatorial value under-measures ground // distance at mid-latitude sites by more than half a percent. function metresPerDegreeLat(latDeg) { const phi = (latDeg * Math.PI) / 180; return 111132.92 - 559.82 * Math.cos(2 * phi) + 1.175 * Math.cos(4 * phi) - 0.0023 * Math.cos(6 * phi); } // A flat-earth frame anchored at the site centre. Over a few // kilometres the error is under 0.1%. export function createEnu(lng0, lat0) { const mPerDegLng = M_PER_DEG_LNG_EQ * Math.cos((lat0 * Math.PI) / 180); const mPerDegLat = metresPerDegreeLat(lat0); return { toENU: (lng, lat) => ({ x: (lng - lng0) * mPerDegLng, y: (lat - lat0) * mPerDegLat, }), }; } export function facadeLengthM(facade) { const [lng1, lat1] = facade.start; const [lng2, lat2] = facade.end; const midLat = (lat1 + lat2) / 2; const dE = (lng2 - lng1) * M_PER_DEG_LNG_EQ * Math.cos((midLat * Math.PI) / 180); const dN = (lat2 - lat1) * metresPerDegreeLat(midLat); return Math.hypot(dE, dN); }

APPENDIX

return { cols, rows, cellWm: lengthM / cols, cellHm: heightM / rows, baseM, heightM, lengthM, cellCount: cols * rows, };

// actual size; targetSizeM is nominal, // since cols and rows are integers

} // ---- Cell addressing -----------------------------------------// UV of a cell centre. i runs left to right from facade.start, j runs // bottom to top from baseM. The drawn wall and the output heatmap // share this convention: an inconsistent one still renders a // valid-looking wall that disagrees with every other layer on it. export function cellUV(grid, i, j) { return { u: (i + 0.5) / grid.cols, v: (j + 0.5) / grid.rows }; } // Cell centre in metres. Interpolated in the metric frame, not in // degrees, so it traces a straight line on the ground. export function cellCenterENU(facade, grid, i, j, enu) { const a = enu.toENU(facade.start[0], facade.start[1]); const b = enu.toENU(facade.end[0], facade.end[1]); const t = (i + 0.5) / grid.cols; return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t, z: grid.baseM + ((j + 0.5) / grid.rows) * grid.heightM, }; }

167


Appendix 04.3 : Svf-math.js Svf-math.js computes how much sky each wall cell can see. Rays are cast across the half-plane in front of the wall, the tallest obstruction along each direction is recorded, and those angles are integrated into a single fraction of the sky dome. Extruded building footprints make every wall vertical, so this is solved as two-dimensional geometry rather than by ray tracing a 3D model. // ============================================================ // SKY VIEW FACTOR // Source: js/lib/svf-math.js // ============================================================

const { bins, stair } = horizon; const maxT = config.maxRadiusM; horizon.count.fill(0); for (let a = 0; a < bins; a++) { const az = normalAzRad + horizon.psis[a];

// ---- The vertical-surface formula -------------------------------// SVF = (1/pi) * sum over azimuths of // cos(psi) dpsi * (1/4)(pi - 2 beta - sin 2 beta) // Vertical surface: an unobstructed value is 0.5, not 1.

// Azimuth convention: north = 0, east = 90, clockwise. In a local // east/north frame that is (sin, cos). const dx = Math.sin(az); const dy = Math.cos(az);

// ---- Parameters -------------------------------------------------const SVF_CONFIG = { azimuthBins: 36, // resolution across the +/-90 deg fan maxRadiusM: 250, // ray length; occluders past it are ignored gridCellM: 25, // occluder index cell, and the walk’s step originOffsetM: 0.5, // push the ray origin off its own wall minHitDistM: 0.5, // ignore hits closer than this maxStairPerAzimuth: 16, }; const SVF_PHYSICAL_MAX = 0.5;

const tEnter = rayBoxEntry(originX, originY, dx, dy, index, maxT); if (tEnter < 0) continue; // ---- Grid walk (Amanatides and Woo) -------------------------// Cells are visited in order, nearest first, and only the // segments bucketed in each are tested. const sx = originX + dx * tEnter; const sy = originY + dy * tEnter; let ci = Math.floor((sx - index.minX) / index.cellM); let cj = Math.floor((sy - index.minY) / index.cellM);

// the ceiling for a vertical surface

// Occluder segments arrive flat, 5 numbers each: x1, y1, x2, y2, height. const OCCLUDER_STRIDE = 5; // ---- What the scan is given -------------------------------------// `index`: a uniform grid over the occluder segments, compressed// sparse-row, `starts` giving each grid cell its slice of `items`. // `skip`: any footprint the ray origin sits inside, excluded. // `rayBoxEntry(px, py, dx, dy, index, maxT)` returns the distance at // which a ray enters that grid’s outer box, 0 inside, -1 on a miss. // ---- Ray and segment ---------------------------------------------

const stepX = Math.sign(dx); const stepY = Math.sign(dy); const tDeltaX = stepX === 0 ? Infinity : index.cellM / Math.abs(dx); const tDeltaY = stepY === 0 ? Infinity : index.cellM / Math.abs(dy); const boundX = index.minX + (ci + (stepX > 0 ? 1 : 0)) * index. cellM; const boundY = index.minY + (cj + (stepY > 0 ? 1 : 0)) * index. cellM; let tMaxX = stepX === 0 ? Infinity : (boundX - originX) / dx; let tMaxY = stepY === 0 ? Infinity : (boundY - originY) / dy;

// Distance along a unit-direction ray to a segment, or -1 for no hit. function rayHitDistance(px, py, dx, dy, ax, ay, bx, by) { const sx = bx - ax; const sy = by - ay; const denom = dx * sy - dy * sx; if (Math.abs(denom) < 1e-12) return -1; // parallel

const base = a * stair; let guard = index.nx + index.ny + 4; while (guard-- > 0) { const cell = cj * index.nx + ci; for (let k = index.starts[cell]; k < index.starts[cell + 1]; k++) {

const qx = ax - px; const qy = ay - py; const u = (qx * dy - qy * dx) / denom; ment if (u < 0 || u > 1) return -1;

// position along the seg-

return (qx * sy - qy * sx) / denom;

// distance along the ray

const s = index.items[k]; if (skip && skip.has(s)) continue;

// a footprint we are in-

side const o = s * OCCLUDER_STRIDE; const t = rayHitDistance( originX, originY, dx, dy, segments[o], segments[o + 1], segments[o + 2], segments[o +

} // ---- The horizon scan -------------------------------------------// One ray per azimuth bin, recording a staircase of hits: sorted by // distance, keeping only hits taller than every nearer one. Observer // height enters at the end, so one scan serves a whole column.

3],

function scanHorizon(index, segments, originX, originY, normalAzRad, horizon, config = SVF_CONFIG, skip = null) {

4]);

); if (t < config.minHitDistM || t > maxT) continue; insertIntoStaircase(horizon, a, base, stair, t, segments[o +

168

}

ALGORITHMIC COOLING


// Advance to whichever cell boundary the ray reaches first. if (tMaxX < tMaxY) { if (tMaxX > maxT) break; ci += stepX; if (ci < 0 || ci >= index.nx) break; tMaxX += tDeltaX; } else { if (tMaxY > maxT) break; cj += stepY; if (cj < 0 || cj >= index.ny) break; tMaxY += tDeltaY; }

// The tallest hit above the observer sets the horizon here. for (let r = 0; r < horizon.count[a]; r++) { const dh = horizon.h[base + r] - z; if (dh <= 0) continue; beta = Math.max(beta, Math.atan2(dh, horizon.d[base + r])); } beta = Math.min(beta, Math.PI / 2); if (a === mid || a === mid - 1) beta0 = Math.max(beta0, beta); sum += Math.cos(horizon.psis[a]) * (Math.PI - 2 * beta - Math.sin(2 * beta)); }

} }

const physical = (sum * dpsi) / (4 * Math.PI);

return horizon;

return { physical: Math.min(Math.max(physical, 0), SVF_PHYSICAL_MAX), beta0Deg: (beta0 * 180) / Math.PI, };

} function insertIntoStaircase(horizon, a, base, stair, t, h) { // Skip anything a nearer hit already dominates. for (let r = 0; r < horizon.count[a]; r++) { if (horizon.d[base + r] <= t && horizon.h[base + r] >= h) return; }

}

// Drop the farther rungs this hit dominates, then append it. let w = 0; for (let r = 0; r < horizon.count[a]; r++) { if (!(horizon.d[base + r] >= t && horizon.h[base + r] <= h)) { horizon.d[base + w] = horizon.d[base + r]; horizon.h[base + w] = horizon.h[base + r]; w++; } } if (w < stair) { horizon.d[base + w] = t; horizon.h[base + w] = h; w++; } horizon.count[a] = w; } // ---- The sky integral -------------------------------------------// No rays cast here; this reads the staircase found above. // Physical sky view factor in [0, 0.5] at observer height z, plus // beta0, the obstruction elevation along the wall normal. function svfFromHorizon(horizon, z) { const { bins, stair } = horizon; const dpsi = Math.PI / bins; let sum = 0; let beta0 = 0; const mid = bins >> 1;

// the bins straddling the normal direction

for (let a = 0; a < bins; a++) { const base = a * stair; let beta = 0;

APPENDIX

169


Appendix 04.4 : View-factors.js View-factors.js casts a cosine-weighted hemisphere of rays from every cell and records what each ray lands on, giving the fraction of that cell’s view occupied by sky, by ground, and by each surrounding wall. The wall fractions are what makes the radiation balance an urban one: a facade exchanges longwave radiation with the buildings opposite it, not with an open horizon. The same cast also records, for each hour of the day, whether the sun reaches the cell, stored as one bit per hour. // ============================================================ // VIEW FACTORS & SUN VISIBILITY // Source: js/lib/view-factors.js // ============================================================

const dy = dy3 / horiz; const slope = dz3 / horiz;

// The ground is a surface, not an absence: a downward ray travels // z / |slope| metres before reaching it. const tLimit = slope < 0 ? Math.min(VF_CONFIG.maxRadiusM, origin.z / -slope) : VF_CONFIG.maxRadiusM;

// ---- Parameters -------------------------------------------------const VF_CONFIG = { rayCount: 256, // rays per cell. This is the TIME knob. sampleSizeM: 2, // spacing of the cells rays are cast FROM seenPatchM: 6, // size of the patches rays are recorded as // landing ON. This is the MEMORY knob. maxHitsPerCell: 128, // distinct patches one cell keeps };

const seg = firstHit(origin, dx, dy, slope, tLimit, segments, index); if (seg < 0) { if (dz3 >= 0) escapedUp++; else escapedDown++; continue; }

// The error that matters is the error on the SUM: longwave exchange // reads sigma * sum(F_j eps_j T_j^4). Individual F_j are noise at // this ray count and are not drawn.

// Hits are recorded against a coarse patch code, not a segment: // a smaller table, and more rays deciding each patch. const code = codeOf(seg, firstHitT, origin.z + firstHitT * slope); hits.set(code, (hits.get(code) ?? 0) + 1);

const DEG = Math.PI / 180; }

// ---- The hemisphere cast ----------------------------------------// Cosine-weighted: the sampling density carries the cos(theta) term, // so every ray counts equally in the fold below. export function castHemisphere({ origin, normalAzDeg, rayCount = VF_CONFIG.rayCount, segments, index, seed = 0, codeOf, }) { const hits = new Map(); let escapedUp = 0; let escapedDown = 0; // North = 0, east = 90, clockwise, so the outward normal is // (sin az, cos az) and the wall’s own direction is (cos az, -sin az). const az = normalAzDeg * DEG; const nx = Math.sin(az), ny = Math.cos(az); const tx = Math.cos(az), ty = -Math.sin(az); const [rot1, rot2] = rotationFromSeed(seed); for (let r = 0; r < rayCount; r++) { // Uniform sample of the unit disk, lifted to the hemisphere. // u1 is the radius squared. let u1 = (r + 0.5) / rayCount + rot1; if (u1 >= 1) u1 -= 1; let u2 = radicalInverse2(r) + rot2; if (u2 >= 1) u2 -= 1; const rr = Math.sqrt(u1); const phi = 2 * Math.PI * u2; const lx = rr * Math.cos(phi); const ly = rr * Math.sin(phi); const lz = Math.sqrt(1 - u1);

// along the wall // world up // along the outward normal

const dx3 = tx * lx + nx * lz; const dy3 = ty * lx + ny * lz; const dz3 = ly; const horiz = Math.sqrt(dx3 * dx3 + dy3 * dy3); const dx = dx3 / horiz;

170

// rise per metre of ground run

return { hits, escapedUp, escapedDown, rayCount }; } // ---- The fold ---------------------------------------------------// Turns one cast into the fractions the radiation balance reads. // fSky comes from the horizon scan, not from this cast; fResidual is // the upward escape minus it, so its sign compares the two engines. // Never clamped. export function foldToFactors(cast, { fSky, maxHits = VF_CONFIG.maxHitsPerCell }) { const m = cast.rayCount; const fGround = cast.escapedDown / m; const fUp = cast.escapedUp / m; // Whatever the cap drops is counted rather than discarded silently. let entries = [...cast.hits.entries()]; let truncatedCount = 0; if (entries.length > maxHits) { entries.sort((a, b) => b[1] - a[1]); for (let i = maxHits; i < entries.length; i++) truncatedCount += entries[i][1]; entries = entries.slice(0, maxHits); } const fj = new Map(); let fFacadeTotal = 0; for (const [code, count] of entries) { const f = count / m; fj.set(code, f); fFacadeTotal += f; } return { fj, fSky,

ALGORITHMIC COOLING


fGround, fResidual: fUp - fSky, fTruncated: truncatedCount / m, fFacadeTotal, }; } // Closure is arithmetic: substituting fResidual collapses the sum to // (hits + up + down) / rayCount = 1. Asserted to catch a double count // or a lost truncation. export function closureError(f) { return f.fFacadeTotal + f.fSky + f.fGround + f.fResidual + f.fTruncated - 1; } // ---- Sun visibility ---------------------------------------------// One bit per time sample. A cell is lit when the sun is above the // horizon, in front of the wall, and unobstructed. export function sunMaskFor(origin, nx, ny, sun, segments, index) { let mask = 0; for (let h = 0; h < sun.samples; h++) { if (!sun.up[h]) continue; // Behind the wall is shaded, and this is the cheapest test. if (sun.dx[h] * nx + sun.dy[h] * ny <= 0) continue; if (firstHit(origin, sun.dx[h], sun.dy[h], sun.slope[h], VF_CONFIG.maxRadiusM, segments, index) >= 0) continue; mask |= 1 << h; } return mask; }

APPENDIX

171


Appendix 04.5 : Facade-materials.js Material-config.js holds the thermal properties of each facade material, taken from the published sources named beside each entry, and maps the colours produced by the material classifier onto those entries. Facade-materials.js then reduces a classified mask image to one material per simulation cell, sixteen samples inside each cell deciding it by majority. // ============================================================ // MATERIAL RESOLUTION // Source: js/workflow/material-config.js, facade-materials.js // ============================================================ // ---- Citations --------------------------------------------------const DB_SRC = { brick: ‘CIBSE Guide A / EN ISO 12524:2000’, concrete: ‘CIBSE Guide A; ASHRAE Ch.26’, steel: ‘ASHRAE Ch.26, metals table’, glass: ‘CIBSE Guide A, window glass’, wood: ‘USDA Wood Handbook, Douglas fir’, stone: ‘CIBSE Guide A, granite’, }; // ---- The property table -----------------------------------------// c specific heat, J/kgK eps emissivity, 0..1 // k conductivity, W/mK alpha solar absorptance // rho density, kg/m3 export const MATERIALS = { brick: { label: ‘Brick’, color: ‘#8c5a44’, c: 800, k: 0.48, rho: 1513, eps: 0.93, alpha: 0.70, source: DB_SRC.brick, }, concrete: { label: ‘Concrete’, color: ‘#9a9a94’, c: 1000, k: 1.65, rho: 2200, eps: 0.90, alpha: 0.65, source: DB_SRC.concrete, },

}, }; // ---- Mask colours -----------------------------------------------// The order is a contract: a match returns a POSITION, that position // is stored per cell, and the legend is drawn from it. export const MASK_COLOURS = { ‘#ff0000’: ‘brick’, ‘#ff00f7’: ‘concrete’, ‘#0008ff’: ‘steel’, ‘#00ffe1’: ‘glass’, ‘#00ff55’: ‘wood’, ‘#eeff00’: ‘stone’, // Second generation of the classifier. ‘#d93626’: ‘brick’, ‘#e626ff’: ‘concrete’, ‘#331ae6’: ‘steel’, ‘#80ffff’: ‘glass’, ‘#80ff66’: ‘wood’, }; // Derived, not written out, so the tables cannot drift apart. The // legend reads this same array. export const MASK_PALETTE = Object.entries(MASK_COLOURS).map(([hex, key]) => ({ key, hex, rgb: [ parseInt(hex.slice(1, 3), 16), parseInt(hex.slice(3, 5), 16), parseInt(hex.slice(5, 7), 16), ], ...MATERIALS[key], })); // ---- Colour matching ---------------------------------------------

// Steel emissivity is a property of the finish, not the metal. // This row is a bare mill finish. steel: { label: ‘Steel’, color: ‘#8a8f94’, c: 465, k: 54, rho: 7833, eps: 0.28, alpha: 0.70, source: DB_SRC.steel, }, // alpha is the glazing absorbing sunlight, not what passes behind. glass: { label: ‘Glass’, color: ‘#5f7f8c’, c: 840, k: 1, rho: 2500, eps: 0.84, alpha: 0.10, source: DB_SRC.glass, }, wood: { label: ‘Wood’, color: ‘#7a5c3c’, c: 1600, k: 0.14, rho: 510, eps: 0.90, alpha: 0.70, source: DB_SRC.wood, }, stone: { label: ‘Stone’, color: ‘#a8a293’, c: 1000, k: 2.8, rho: 2600, eps: 0.90, alpha: 0.65, source: DB_SRC.stone,

172

const MATERIAL_MATCH_CONFIG = { maxDistance: 40, // max RGB distance from a mask colour minAlpha: 128, // below this a pixel means “no material here” subSamples: 4, // samples per cell edge, so 16 votes per cell }; // 2 * maxDistance must stay at or below the distance between the // closest pair of mask colours, 82.76, giving a ceiling of 41.38. const MAX_DISTANCE_SQ = MATERIAL_MATCH_CONFIG.maxDistance ** 2; // A MASK_PALETTE index, or -1 when nothing is close enough. Nearest // colour rather than exact: a resampled PNG carries pixels a few units // off. The threshold is squared above, so no square root here. export function matchMaterialIndex(r, g, b, maxDistanceSq = MAX_DISTANCE_SQ) { let best = -1; let bestD = Infinity; for (let m = 0; m < MASK_PALETTE.length; m++) { const c = MASK_PALETTE[m].rgb; const dr = r - c[0]; const dg = g - c[1]; const db = b - c[2];

ALGORITHMIC COOLING


const d

= dr * dr + dg * dg + db * db; votes[m]++; voted++;

if (d < bestD) { bestD = d; best = m; } }

} }

return bestD <= maxDistanceSq ? best : -1; }

if (voted === 0) continue;

// ---- Reducing the mask to cells ---------------------------------// 4 samples per cell edge on a 2 m cell = a 0.5 m sampling interval. // The image is not read again after this. Known bias: a window // narrower than a cell is outvoted by the wall around it.

let best = 0; for (let m = 1; m < votes.length; m++) { if (votes[m] > votes[best]) best = m; } index[j * cols + i] = best;

// Per-cell palette indices, laid out j * cols + i with j = 0 at the // BOTTOM of the wall. -1 is transparent or unmatched: no prediction. function sampleMaskToCells(img, vMax, cols, rows, cfg = MATERIAL_MATCH_ CONFIG) { const S = cfg.subSamples; const w = cols * S; const h = rows * S;

} } return index; }

const canvas = document.createElement(‘canvas’); canvas.width = w; canvas.height = h; const ctx = canvas.getContext(‘2d’, { willReadFrequently: true }); // Nearest-neighbour downscale: a categorical image has no // meaningful average. ctx.imageSmoothingEnabled = false; // The wall occupies the bottom vMax of the image, the same crop the // mesh UVs apply. const sy = img.naturalHeight * (1 - vMax); const sh = img.naturalHeight * vMax; ctx.drawImage(img, 0, sy, img.naturalWidth, sh, 0, 0, w, h); const { data } = ctx.getImageData(0, 0, w, h); const index = new Int8Array(cols * rows).fill(-1); const votes = new Int32Array(MASK_PALETTE.length); for (let j = 0; j < rows; j++) { for (let i = 0; i < cols; i++) { votes.fill(0); let voted = 0; for (let sj = 0; sj < S; sj++) { // Canvas row 0 is the TOP of the image; the model’s v = 0 is // the BOTTOM of the wall. const py = (rows - 1 - j) * S + sj; for (let si = 0; si < S; si++) { const p = (py * w + i * S + si) * 4; if (data[p + 3] < cfg.minAlpha) continue;

// cut-out

sky const m = matchMaterialIndex(data[p], data[p + 1], data[p + 2]); if (m < 0) continue;

APPENDIX

// unmatched

173


Appendix 04.6 : Sky.js Sky.js supplies everything the simulation needs from outside the site geometry: the position of the sun at each hour, and the direct, diffuse and global irradiance, air temperature and sky temperature recorded for that hour. The hourly values are read from a standard weather file for London. Solar geometry is the one part of the chain with an external reference, sunrise and sunset being published figures. // ============================================================ // SUN & WEATHER // Source: js/lib/sky.js // ============================================================ // ---- Parameters -------------------------------------------------const WEATHER_CONFIG = { epwUrl: ‘assets/weather/GBR_ENG_London...TMYx.epw’, dayOfYear: 180, // 29 June: the file’s highest air temperature, // and also its highest direct solar total latDeg: 51.50, lonDeg: -0.12, // east positive tzOffsetH: 0, // verified against the file’s own astronomical // column, not guessed from when irradiance starts };

} // The sun’s position, seen from one ground point at one instant. // altitudeDeg is geometric and negative at night, and not clamped. export function sunPosition({ latDeg, lonDeg, dayOfYear, hourLocal, tzOffsetH, year }) { const jd = julianDayUT(year, dayOfYear, hourLocal - tzOffsetH); const { declDeg, eqTimeMin } = solarTerms(jd); // True solar time: clock time corrected for the equation of time and // for the site’s distance from its zone meridian, 4 min per degree. const trueSolarMin = mod(hourLocal * 60 + eqTimeMin + 4 * lonDeg - 60 * tzOffsetH, 1440); const haDeg = trueSolarMin / 4 - 180; // negative before solar noon const latR = latDeg * DEG; const declR = declDeg * DEG; const cosZen = clamp( Math.sin(latR) * Math.sin(declR) + Math.cos(latR) * Math.cos(declR) * Math.cos(haDeg * DEG), -1, 1);

const SIGMA = 5.67e-8; const DEG = Math.PI / 180; const RAD = 180 / Math.PI; // ---- Solar position ---------------------------------------------// Declination and the equation of time, evaluated at the instant // asked about rather than once per day. function solarTerms(jd) { const jc = (jd - 2451545) / 36525; // Julian centuries from J2000 const L0 = mod(280.46646 + jc * (36000.76983 + jc * 0.0003032), 360); const M = 357.52911 + jc * (35999.05029 - 0.0001537 * jc); const e = 0.016708634 - jc * (0.000042037 + 0.0000001267 * jc); const C = Math.sin(M * DEG) * (1.914602 - jc * (0.004817 + 0.000014 * jc)) + Math.sin(2 * M * DEG) * (0.019993 - 0.000101 * jc) + Math.sin(3 * M * DEG) * 0.000289;

const zenR = Math.acos(cosZen); const altitudeDeg = 90 - zenR * RAD; // The arccosine gives an angle away from due south; which side of // south is decided by the hour angle. const sinZen = Math.sin(zenR); const cosAz = clamp( (Math.sin(latR) * cosZen - Math.sin(declR)) / (Math.cos(latR) * sinZen), -1, 1); const az = Math.acos(cosAz) * RAD; const azimuthDeg = haDeg > 0 ? mod(az + 180, 360) : mod(540 - az, 360); const altR = altitudeDeg * DEG; const azR = azimuthDeg * DEG;

const appLong = L0 + C - 0.00569 - 0.00478 * Math.sin((125.04 - 1934.136 * jc) * DEG);

return { altitudeDeg, azimuthDeg, // referenced to TRUE north dir: { x: Math.cos(altR) * Math.sin(azR), // east y: Math.cos(altR) * Math.cos(azR), // north z: Math.sin(altR), // up }, };

const meanObliq = 23 + (26 + (21.448 - jc * (46.815 + jc * (0.00059 - jc * 0.001813))) / 60) / 60; const obliqCorr = meanObliq + 0.00256 * Math.cos((125.04 - 1934.136 * jc) * DEG); const declDeg = Math.asin( Math.sin(obliqCorr * DEG) * Math.sin(appLong * DEG)) * RAD; const y = Math.tan((obliqCorr / 2) * DEG) ** 2; const eqTimeMin = 4 * RAD * ( y * Math.sin(2 * L0 * DEG) - 2 * e * Math.sin(M * DEG) + 4 * e * y * Math.sin(M * DEG) * Math.cos(2 * L0 * DEG) - 0.5 * y * y * Math.sin(4 * L0 * DEG) - 1.25 * e * e * Math.sin(2 * M * DEG) );

} // ---- Sky temperature --------------------------------------------// Inverts the Stefan-Boltzmann law, treating the sky as a black body // with the downwelling flux the weather file recorded. Returned in // KELVIN: every use downstream raises it to the fourth power. // Scale: 345 W/m2 is about 279 K, near 6 degC. export function skyTempK(irHorizW) { return (irHorizW / SIGMA) ** 0.25; }

return { declDeg, eqTimeMin };

174

ALGORITHMIC COOLING


// ---- Weather file -----------------------------------------------// Reads the 24 rows of one day out of an EPW file. export function parseEpwDay(text, dayOfYear) { const rows = []; for (const raw of text.split(/\r?\n/)) { const f = raw.trim().split(‘,’); if (f.length < EPW_MIN_FIELDS) continue;

const dx = new Float32Array(samples); const dy = new Float32Array(samples); const slope = new Float32Array(samples); for (let h = 0; h < samples; h++) { const { altitudeDeg, dir } = sunPosition({ ...weather, hourLocal: h }); if (altitudeDeg <= 0) continue;

// header or comment const horiz = Math.hypot(dir.x, dir.y); up[h] = 1; dx[h] = dir.x / horiz; dy[h] = dir.y / horiz; slope[h] = dir.z / horiz;

const month = Number(f[EPW_FIELD.month]); const day = Number(f[EPW_FIELD.day]); if (!(month >= 1 && month <= 12)) continue; // Derived from the row’s own month and day, not from its position // in the file. if (dayOfYearOf(month, day) !== dayOfYear) continue;

} return { samples, up, dx, dy, slope }; }

// EPW hours are 1..24. Copied through as 0-based, the whole day // shifts by one hour. const epwHour = Number(f[EPW_FIELD.hour]); const row = { hour: epwHour - 1, midHourLocal: epwHour - 0.5, dryBulbC: Number(f[EPW_FIELD.dryBulbC]), dni: Number(f[EPW_FIELD.dni]), dhi: Number(f[EPW_FIELD.dhi]), ghi: Number(f[EPW_FIELD.ghi]), irHorizW: Number(f[EPW_FIELD.irHorizW]), };

// direct normal // diffuse horizontal // global horizontal // downwelling infrared

// A missing value throws. Substituting one is a decision about the // weather file, not a parser fix. for (const [key, sentinel] of Object.entries(EPW_MISSING)) { if (!Number.isFinite(row[key]) || row[key] >= sentinel) { throw new Error(`sky: EPW ${key} is missing at ${month}/${day} hour ${epwHour}.`); } } rows.push(row); } if (rows.length !== 24) { throw new Error(`sky: day ${dayOfYear} yielded ${rows.length} rows, expected 24`); } return rows.sort((a, b) => a.hour - b.hour); } // ---- Per-hour sun directions ------------------------------------// Precomputed for the shading pass: one ray toward the sun per cell // per hour. Hours with the sun below the horizon are marked down. export function buildSunSamples(weather = WEATHER_CONFIG, samples = 24) { const up = new Uint8Array(samples);

APPENDIX

175


Appendix 04.7 : Predict.js Predict.js gathers each cell’s position, orientation, sky view factor and material properties into a single input tensor, scaled against the domains the surrogate model was trained on. It then runs the model for one hour of the simulated day and converts each score back into degrees Celsius. Inference is executed in the browser, and a cell whose mask matched no material is left unanswered rather than given a substitute value. // ============================================================ // SURROGATE MODEL // Source: js/workflow/predict.js, js/simulation-config.js // ============================================================ // ---- Parameters: the model contract -----------------------------const ST_MODEL = { modelUrl: ‘assets/models/facade_st_v5.onnx’, featureInputs: [ ‘Time’, ‘AirTemperature’, ‘X’, ‘Y’, ‘Orientation’, ‘SVF’, ‘M_Density’, ‘M_Conductivity’, ‘M_ThermalCapacity’, ‘M_Emissivity’, ‘M_SolarAbsorption’, ], // Which material property feeds which model input. materialInputs: { M_Density: ‘density’, M_Conductivity: ‘conductivity’, M_ThermalCapacity: ‘thermalCapacity’, // volumetric: rho * c M_Emissivity: ‘emissivity’, M_SolarAbsorption: ‘absorptance’, }, // A wrong domain breaks nothing visible: a tree ensemble answers // from its outermost leaf. These were verified against the model’s // own split thresholds, not against the render. inputDomains: { Time: [0, 23], // hour of day AirTemperature: [15, 33.2], // degC, the simulated day Orientation: [0, 360], // deg, grid north = 0 SVF: [0, 50], // percent of sky, not 0..1 M_Density: [480, 11300], // kg/m3 M_Conductivity: [0.14, 380], // W/mK M_ThermalCapacity: [768000, 3642345], // J/m3K M_Emissivity: [0.2, 0.93], M_SolarAbsorption: [0.6, 0.95], X: [0, 1], // position within the site Y: [0, 1], }, }; // ---- Normalisation ----------------------------------------------// No clamping. The training set holds values outside these domains: // glass absorptance 0.10 normalises to -1.43, and the model’s split // thresholds show it was trained on that value. export function normalize(value, [min, max]) { return (value - min) / (max - min); } export function denormalize(unit, [min, max]) { return min + unit * (max - min); } // The scan gives a fraction of the physical maximum; the model was // trained on a percentage of the sky dome. Returns a RAW value, which // the caller normalises like every other column.

176

export function adaptSvf(svf01) { return svf01 * 50; } // ---- Geometry columns -------------------------------------------// Fills every column that does not change over the day. Time and // AirTemperature are the scenario, written by the run step below. export async function prepareBatch(facades, { contract, grids, svfResults, materials }) { // A facade is usable only with an orientation, a grid, an SVF field // and a material field. A wall missing any is skipped whole. const usable = []; for (const facade of facades) { const grid = grids.get(facade); const svf = svfResults.get(facade); const material = materials.get(facade); if (!Number.isFinite(facade.normalAzDeg) || !grid || !svf || !material) continue; usable.push({ facade, grid, svf, material }); } // Prefix offsets: offsets[f] is where facade f’s cells begin in the // flat batch. const offsets = new Int32Array(usable.length + 1); for (let f = 0; f < usable.length; f++) { offsets[f + 1] = offsets[f] + usable[f].grid.cellCount; } const rows = offsets[usable.length]; // One column per declared feature input, allocated from the contract // rather than as named locals. const col = {}; for (const name of contract.featureInputs) col[name] = new Float32Array(rows); // The material columns are resolved once per model, not per cell. const matCols = Object.entries(contract.materialInputs).map( ([inputName, quantityKey]) => ({ out: col[inputName], read: MATERIAL_QUANTITIES[quantityKey], domain: contract.inputDomains[inputName], }), ); // A cell whose mask matched nothing still occupies a row: the tensor // stays rectangular. Its score is discarded later. const cellHasMaterial = new Uint8Array(rows); for (let f = 0; f < usable.length; f++) { const { facade, grid, svf, material } = usable[f]; const orientation = normalize(facade.normalAzDeg, contract.inputDomains.Orientation); const base = offsets[f]; for (let j = 0; j < grid.rows; j++) { for (let i = 0; i < grid.cols; i++) { const k = j * grid.cols + i;

ALGORITHMIC COOLING


const r = base + k; const { u, v } = cellUV(grid, i, j);

for (let f = 0; f < usable.length; f++) { const { facade, grid } = usable[f]; const base = offsets[f];

col.X[r] = normalize(u, contract.inputDomains.X); col.Y[r] = normalize(v, contract.inputDomains.Y); col.Orientation[r] = orientation; col.SVF[r] = normalize(adaptSvf(svf.svf01[k]), contract.inputDomains.SVF);

const cells = into ?? new Float32Array(grid.cellCount); const cellBase = into ? intoOffset + base : 0; for (let k = 0; k < grid.cellCount; k++) { const r = base + k;

// A negative index means the mask said nothing here. const m = material.index[k]; cellHasMaterial[r] = m >= 0 ? 1 : 0; if (m < 0) continue;

// NaN, not a substitute: the heatmap draws a non-finite cell // transparent, so it reads as unanswered. if (cellHasMaterial[r] === 0) { cells[cellBase + k] = NaN; continue; }

// Properties are read from the palette here rather than // pre-baked into per-cell arrays: one source per number. const mat = material.palette[m]; for (const mc of matCols) mc.out[r] = normalize(mc.read(mat), mc.domain); } } } return { contract, usable, offsets, rows, col, cellHasMaterial }; } // ---- Parameters -------------------------------------------------const OUTPUT_DOMAIN_C = [5, 115]; // degC; the inverse of the input scaling

// The inverse of the input scaling, and the only thing done // to a score. cells[cellBase + k] = denormalize(scores[r], OUTPUT_DOMAIN_C); } if (!into) out.set(facade, { cells, width: grid.cols, height: grid. rows }); } return { grids: into ? null : out, cells: rows }; }

// ---- One scenario -----------------------------------------------// `prepared` is reusable; this runs once per hour. `into` lets the day // sweep supply its own flat buffer. export async function runBatch(prepared, inputs, { into = null, intoOffset = 0 } = {}) { const { contract, usable, offsets, rows, col, cellHasMaterial } = prepared; // Filled in place, over the buffers the prepare step allocated: // two fills instead of a rebuild. col.Time.fill(normalize(inputs.timeHours, contract.inputDomains.Time)); col.AirTemperature.fill( normalize(inputs.airTemperatureC, contract.inputDomains.AirTemperature), ); const feeds = {}; for (const name of contract.featureInputs) { feeds[name] = new ort.Tensor(‘float32’, col[name], [rows, 1]); } const output = await session.run(feeds, [contract.outputName]); const scores = output[contract.outputName].data; // Keyed by the facade object: one facade_id covers several captured // wall segments. const out = new Map();

APPENDIX

177


Appendix 04.8 : Sweep.js Sweep.js runs the surrogate across all twenty-four hours in a single pass and stores the results in one buffer. Only the hour and the air temperature change between runs, so the geometry is prepared once and any hour can then be read back without further inference.

// ============================================================ // DAY SWEEP // Source: js/workflow/sweep.js // ============================================================

timeHours: h, airTemperatureC: airC, }, { into: values, intoOffset: h * cellCount }); // Answered cells only: a site legitimately has NaN cells where // nothing was observed. let sum = 0; let counted = 0; const base = h * cellCount; for (let k = 0; k < cellCount; k++) { const v = values[base + k]; if (!Number.isFinite(v)) continue; sum += v; counted++; } hourMeans[h] = counted > 0 ? sum / counted : NaN;

// ---- Parameters -------------------------------------------------const SWEEP_CONFIG = { samplesPerFrame: 1, // samples computed before yielding a frame }; // Yielding lets the browser paint the progress line. const nextFrame = () => new Promise((r) => requestAnimationFrame(r)); // ---- The sweep --------------------------------------------------export async function sweepDay({ facades, contract, grids, svfResults, materials }) { // The geometry half runs once; per sample it would dominate. const prepared = await prepareBatch(facades, { contract, grids, svfResults, materials, }); const samples = 24; const cellCount = prepared.rows; // Sample-major: one hour is a subarray view over the same buffer, // so a slider drag reads rather than walks. const values = new Float32Array(samples * cellCount); // Where each facade sits inside one sample, built from the same // offsets the inference writes into. const index = new Map(); for (let f = 0; f < prepared.usable.length; f++) { const { facade, grid } = prepared.usable[f]; index.set(facade, { offset: prepared.offsets[f], width: grid.cols, height: grid.rows, cellCount: grid.cellCount, }); }

if (h < samples - 1) await nextFrame(); } return { samples, cellCount, values, index, hourMeans, hoursOutsideAirRange }; } // ---- Reading one hour back --------------------------------------// One sample’s field as a view over the sweep buffer, allocating // nothing. This is what the time slider calls. export function gridsAtHour(sweep, hour) { const base = hour * sweep.cellCount; const grids = new Map(); for (const [facade, slot] of sweep.index) { grids.set(facade, { cells: sweep.values.subarray(base + slot.offset, base + slot.offset + slot.cellCount), width: slot.width, height: slot.height, }); } return grids; }

const hourMeans = new Float32Array(samples); // Hours outside the model’s trained air range are counted, not // clamped: a tree ensemble answers from its outermost leaf. const airRange = contract.inputDomains.AirTemperature; let hoursOutsideAirRange = 0; for (let h = 0; h < samples; h++) { // Decided here and nowhere else, so the readout and the model // read the same number, written from the weather file. const airC = diurnalAirC(h); if (airC < airRange[0] || airC > airRange[1]) hoursOutsideAirRange++; await runBatch(prepared, {

178

ALGORITHMIC COOLING


Appendix 04.9 : Radiation.js Radiation.js computes the radiative balance on one wall cell for one hour. Shortwave gain from the sun, the sky, the ground and the surrounding walls is summed against the longwave exchange with those same surroundings, and the energy leaving the surface is reported alongside the net gain.

// ============================================================ // RADIATION BALANCE // Source: js/lib/radiation.js // ============================================================ // ---- Parameters -------------------------------------------------const RADIATION_CONFIG = { SIGMA: 5.67e-8, // Stefan-Boltzmann constant, W/m2K4 groundAlbedo: 0.20, // aged asphalt and concrete paving groundTempOffsetK: 0, // ground surface taken as air temperature minKelvinGuard: 200, // see the guard below }; // No convection term: at a given temperature difference it is nearly // identical for every material. This is a radiative net flux, not a // complete energy balance. // ---- The Kelvin guard -------------------------------------------// Celsius leaking into a fourth power gives a plausible number rather // than a failure: sigma * 38.4^4 = 0.000123, sigma * 311.55^4 = 534. function pow4K(tK, what) { if (!(tK >= RADIATION_CONFIG.minKelvinGuard)) { throw new Error(`radiation: ${what} = ${tK} K is below the Kelvin guard.`);} const t2 = tK * tK; return t2 * t2; }

// ---- Longwave -------------------------------------------------const tGroundK = tAirC + C_TO_K + RADIATION_CONFIG.groundTempOffsetK; const skyT4 = pow4K(tSkyK, ‘tSkyK’); const groundT4 = pow4K(tGroundK, ‘ground’); const emitted = epsilon * S * pow4K(tSurfC + C_TO_K, ‘tSurfC’); const fromSky = epsilon * fSky * S * skyT4; const fromGround = epsilon * fGround * S * groundT4; // Building-to-building exchange, the term a single-building // simulation does not have. A missing neighbour throws: the patch // and cell index spaces overlap numerically. let neighT4 = 0; for (const [key, f] of fj) { const tC = tNeighbourC.get(key); if (tC === undefined) { throw new Error(`radiation: no temperature for neighbour ${key}.`); } neighT4 += f * pow4K(tC + C_TO_K, `tNeighbourC[${key}]`); } const fromNeighbours = neighT4 * (epsilon * S); // Seen but with no temperature available. Air temperature is the // neutral choice. const fromResidual = epsilon * fResidual * S * groundT4; const qLW = -emitted + fromSky + fromGround + fromNeighbours + fromResidual;

const C_TO_K = 273.15; // Incident, not absorbed: no alpha, no epsilon. That is what makes // the closure below a test rather than a restatement. const lwIn = (fSky * skyT4 + fGround * groundT4 + neighT4 + fResidual * groundT4) * S;

// ---- The balance ------------------------------------------------// f* hemisphere fractions, from the view factors // tSurfC, tNeighbourC temperatures, from the day sweep // alphaSol, epsilon, tAirC, tSkyK, dni, dhi, ghi

// Radiant load: the energy sent back into the street. The third // term is the one most often dropped; bare steel at epsilon 0.28 // reflects 72% of the infrared reaching it. const qRL = (1 - alphaSol) * swIn + emitted + (1 - epsilon) * lwIn;

export function cellRadiation({ fSky, fGround, fj, fResidual, sunVisible, cosIncidence, tSurfC, tNeighbourC, alphaSol, epsilon, tAirC, tSkyK, dni, dhi, ghi, swInNeighbourW = 0, }) { const S = RADIATION_CONFIG.SIGMA;

// Closure identity, cell by cell and hour by hour: // swIn + lwIn === qNet + qRL // The same balance with every neighbour view factor set to zero: // the difference is the size of the urban coupling. Their share of // the hemisphere becomes sky. const neighbourShareAsSky = epsilon * fjTotal * S * skyT4; const qLWnoNeighbour = -emitted + fromSky + fromGround + fromResidual + neighbourShareAsSky; return { qSW, qLW, qNet: qSW + qLW, qRL, qSWIn: swIn, qLWIn: lwIn, qLWnoNeighbour, };

// ---- Shortwave ------------------------------------------------// A negative cosine means the sun is behind the wall, where the // direct beam is absent rather than reversed. const cosI = cosIncidence > 0 ? cosIncidence : 0; const swDirect = sunVisible ? dni * cosI : 0; const swDiffuse = dhi * fSky; // Reflection off the neighbours, rho = 1 - alpha. This cell’s // absorptance stands in for the neighbours’ own. let fjTotal = 0; for (const v of fj.values()) fjTotal += v; const swReflNeighbour = fjTotal * (1 - alphaSol) * swInNeighbourW; const swReflGround = fGround * RADIATION_CONFIG.groundAlbedo * ghi; const swIn = swDirect + swDiffuse + swReflNeighbour + swReflGround; const qSW = alphaSol * swIn;

APPENDIX

}

179


Appendix 04.10 : Radiation-run.js Radiation-run.js assembles the inputs that balance requires, the view factors, recorded against coarse patches, are matched to the temperatures held per finer cell, the sun’s position is resolved for each hour, and each hour is then solved in two passes, because the shortwave a wall reflects onto its neighbours depends on what those neighbours are themselves receiving. The results are written hour by hour into one buffer, so any hour can be read back without recomputation.

// ============================================================ // RADIATION RUN // Source: js/workflow/radiation-run.js // ============================================================ // ---- The patch fold ---------------------------------------------// The view factor pass records hits as coarse PATCH codes; the day // sweep produces one temperature per finer CELL. The two index spaces // overlap numerically, so a wrong fold resolves instead of throwing. // A cell maps to the patch containing its centre, using exactly the // arithmetic the ray cast used to assign the hit in the first place. export function patchOfCell(i, j, cols, rows, patchBase, patchCols, patchRows) { const pc = clampInt(Math.floor(((i + 0.5) / cols) * patchCols), patchCols); const pr = clampInt(Math.floor(((j + 0.5) / rows) * patchRows), patchRows); return patchBase + pr * patchCols + pc; } // Averages a per-cell field onto patches. Non-finite cells are skipped // rather than averaged in: one NaN would spread to a whole patch. function foldToPatches(plan, source, out, counts) { out.fill(0); counts.fill(0); for (const f of plan.facades) { for (let k = 0; k < f.cellCount; k++) { const v = source[f.cellBase + k]; if (!Number.isFinite(v)) continue; out[f.patchOfCell[k]] += v; counts[f.patchOfCell[k]]++; } } for (let p = 0; p < out.length; p++) { if (counts[p] > 0) out[p] /= counts[p]; }

const cosIncidence = new Float32Array(n); const sunLit = new Uint8Array(n); const sw1 = new Float32Array(n); const swNeighbour = new Float32Array(n); for (let h = 0; h < samples; h++) { const w = day.rows[h]; const tSkyK = skyTempK(w.irHorizW); const sun = sunPosition({ ...WEATHER_CONFIG, hourLocal: h }); const up = sun.altitudeDeg > 0; const bit = 1 << h; // A vertical wall’s normal has no z, so the sun’s vertical // component drops out of the dot product. The sun mask already // holds “above the horizon” and “behind this wall”. for (let c = 0; c < n; c++) { cosIncidence[c] = up ? normalX[c] * sun.dir.x + normalY[c] * sun. dir.y : 0; sunLit[c] = (sunMaskOf[c] & bit) !== 0 ? 1 : 0; } // This hour’s temperatures, gathered from the sweep and folded. const sweepBase = h * sweep.cellCount; for (const f of plan.facades) { for (let k = 0; k < f.cellCount; k++) { cellTempC[f.cellBase + k] = sweep.values[sweepBase + f.sweepOffset + k]; } } foldToPatches(plan, cellTempC, patchTempC, counts); // A patch no cell landed on has no temperature. Left at 0 it is a // cold spot pulling heat out of everything that sees it. Air // temperature is the neutral filling. for (let p = 0; p < patchTempC.length; p++) { if (counts[p] === 0) patchTempC[p] = w.dryBulbC; }

} // ---- The run ----------------------------------------------------export async function runRadiation({ plan, sweep, day, samples = 24 }) { const n = plan.cellCount; // Hour-major, the same layout the day sweep uses, so reading one // hour back is a view rather than a scan. const values = new Float32Array(samples * n); // radiant load const swIn = new Float32Array(samples * n); const lwIn = new Float32Array(samples * n); const cellTempC = new Float32Array(n); const patchTempC = new Float32Array(plan.patchTotal); const patchSw = new Float32Array(plan.patchTotal); const counts = new Int32Array(plan.patchTotal);

180

// ---- Pass 1: direct, diffuse and ground only ------------------// Two passes, because the neighbour reflection term depends on what // the neighbours are receiving. Read inside one pass it returns the // previous hour’s residue. shortwavePass1({ count: n, fSky, fGround, cosIncidence, sunLit, dni: w.dni, dhi: w.dhi, ghi: w.ghi, out: sw1, }); foldToPatches(plan, sw1, patchSw, counts); // What each cell’s neighbours are carrying, view-factor weighted. // The average, not the sum: the balance multiplies by the total // view factor again. for (let c = 0; c < n; c++) { let acc = 0; let tot = 0;

ALGORITHMIC COOLING


for (let k = rowStart[c]; k < rowEnd[c]; k++) { acc += weights[k] * patchSw[codes[k]]; tot += weights[k]; } swNeighbour[c] = tot > 0 ? acc / tot : 0; } // ---- Pass 2: the full balance --------------------------------radiationBatch({ count: n, fSky, fGround, fResidual, tSurfC: cellTempC, alphaSol, epsilon, cosIncidence, sunLit, swInNeighbourW: swNeighbour, rowStart, rowEnd, codes, weights, patchTempC, tAirC: w.dryBulbC, tSkyK, dni: w.dni, dhi: w.dhi, ghi: w.ghi, outRL: values.subarray(h * n, (h + 1) * n), outSWIn: swIn.subarray(h * n, (h + 1) * n), outLWIn: lwIn.subarray(h * n, (h + 1) * n), }); await nextFrame(); } // swIn and lwIn are kept so the panel can break a reading down into // its components without running the physics a second time. return { samples, cellCount: n, values, swIn, lwIn, index: plan.index }; }

APPENDIX

181


Appendix 04.11 : Sampling.js Sampling.js spreads each wall cell’s reading onto the ground around it, weighted by distance and by the direction the wall faces. Ground further than a fixed radius from any wall is left without a value, so the outer boundary of the field states what was measured. // ============================================================ // GROUND FIELD // Source: js/viewer/sampling.js // ============================================================ // ---- Parameters -------------------------------------------------const FIELD_CONFIG = { cellSizeM: 2, // ground grid square edge, metres kernel: ‘wendland’, // compact support, C2 continuous splatRadiusM: 8, // how far one wall cell splats valueRadiusM: 14, // total reach after the isotropic blur clipDistanceM: 12, // beyond this, no claim is made normalPower: 1, // exponent on the facing cosine mask padCells: 8, // grid margin, in squares }; // padCells * cellSizeM must cover clipDistanceM, or the outer contour // ring is cut against the grid edge and cannot close. // ---- The kernel -------------------------------------------------// Wendland: compact support, continuous at the boundary. A hard // cutoff steps the weight to zero at the radius, and a step in a // field about to be contoured draws a curve of the parameter. function wendland(r) { if (r >= 1) return 0; const s = 1 - r; return s * s * s * s * (4 * r + 1); } // ---- Separable blur ---------------------------------------------// A normalised 1D Gaussian in grid squares, truncated at three sigma. function gaussianTaps(sigmaCells) { const reach = Math.max(1, Math.ceil(sigmaCells * 3)); const taps = new Float64Array(reach * 2 + 1); const denom = 2 * sigmaCells * sigmaCells; let total = 0; for (let i = -reach; i <= reach; i++) { const w = Math.exp(-(i * i) / denom); taps[i + reach] = w; total += w; } for (let i = 0; i < taps.length; i++) taps[i] /= total; return { taps, reach }; } // Two 1D passes in place of one 2D convolution: at sigma 2.3 squares, // 30 multiplies per square rather than 225. Out-of-range taps are // dropped, which is exact because both arrays are zero outside. function blurSeparable(src, cols, rows, taps, reach, scratch) { for (let r = 0; r < rows; r++) { const base = r * cols; for (let c = 0; c < cols; c++) { let acc = 0; const lo = Math.max(-reach, -c); const hi = Math.min(reach, cols - 1 - c); for (let d = lo; d <= hi; d++) acc += src[base + c + d] * taps[d + reach]; scratch[base + c] = acc; }}

182

for (let r = 0; r < rows; r++) { const lo = Math.max(-reach, -r); const hi = Math.min(reach, rows - 1 - r); for (let c = 0; c < cols; c++) { let acc = 0; for (let d = lo; d <= hi; d++) { acc += scratch[(r + d) * cols + c] * taps[d + reach]; } src[r * cols + c] = acc; } } } // ---- Exact Euclidean distance transform -------------------------// Felzenszwalb and Huttenlocher: O(n) in the squares, two passes of a // 1D lower envelope. `seeds` is 1 where the distance is zero. function distanceTransform(seeds, cols, rows) { const INF = 1e20; const d2 = new Float64Array(cols * rows); for (let i = 0; i < d2.length; i++) d2[i] = seeds[i] ? 0 : INF; const len = Math.max(cols, rows); const f = new Float64Array(len); const dst = new Float64Array(len); const v = new Int32Array(len); const z = new Float64Array(len + 1);

// the sampled function // its transform // parabola vertices // envelope boundaries

// The 1D transform of a sampled function is the lower envelope of // the parabolas rooted at each sample. const transform1d = (n) => { let k = 0; v[0] = 0; z[0] = -INF; z[1] = INF; for (let q = 1; q < n; q++) { let s = ((f[q] + q * q) - (f[v[k]] + v[k] * v[k])) / (2 * q - 2 * v[k]); while (s <= z[k]) { k--; s = ((f[q] + q * q) - (f[v[k]] + v[k] * v[k])) / (2 * q - 2 * v[k]); } k++; v[k] = q; z[k] = s; z[k + 1] = INF; } k = 0; for (let q = 0; q < n; q++) { while (z[k + 1] < q) k++; const dq = q - v[k]; dst[q] = dq * dq + f[v[k]]; } }; // Columns first, then rows. The 2D transform is the composition of // the two 1D ones. for (let c = 0; c < cols; c++) { for (let r = 0; r < rows; r++) f[r] = d2[r * cols + c];

ALGORITHMIC COOLING


transform1d(rows); for (let r = 0; r < rows; r++) d2[r * cols + c] = dst[r];

const cy = Math.floor((py - originY) / cellSizeM);

} for (let r = 0; r < rows; r++) { const base = r * cols; for (let c = 0; c < cols; c++) f[c] = d2[base + c]; transform1d(cols); for (let c = 0; c < cols; c++) d2[base + c] = dst[c]; }

for (let gy = cy - reach; gy <= cy + reach; gy++) { if (gy < 0 || gy >= rows) continue; const dy = originY + (gy + 0.5) * cellSizeM - py; for (let gx = cx - reach; gx <= cx + reach; gx++) { if (gx < 0 || gx >= cols) continue; const dx = originX + (gx + 0.5) * cellSizeM - px;

const out = new Float32Array(cols * rows); for (let i = 0; i < out.length; i++) { out[i] = d2[i] >= INF ? Infinity : Math.sqrt(d2[i]); } return out;

// Squared, then sqrt rather than hypot. This loop runs three // and a half million times on a real site. Measured: 72 ms // with hypot, 26 ms without. const d2 = dx * dx + dy * dy; if (d2 >= splat2) continue; const dist = Math.sqrt(d2);

} // ---- Grid extent ------------------------------------------------// The origin is snapped to a multiple of the square size, so the grid // does not shift under the site when one wall enters or leaves it. function gridExtentFor(cells, cfg) { let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity; for (let k = 0; k < cells.count; k++) { minX = Math.min(minX, cells.x[k]); maxX = Math.max(maxX, cells.x[k]); minY = Math.min(minY, cells.y[k]); maxY = Math.max(maxY, cells.y[k]); }

let w = wendland(dist / splatRadiusM); // The facing mask is a physical correction. An isotropic // kernel spreads a south wall’s 48 degC into the massing // behind it, and averages 48 and 36 across a 15 m street. // Coverage falls from 63% to 35%. if (dist > nearM) { const cos = (nx * dx + ny * dy) / dist; // Behind the wall: no weight at all. if (cos <= 0) continue;

const { cellSizeM, padCells } = cfg; const originX = Math.floor(minX / cellSizeM - padCells) * cellSizeM; const originY = Math.floor(minY / cellSizeM - padCells) * cellSizeM;

w *= normalPower === 1 ? cos : Math.pow(cos, normalPower); } const idx = gy * cols + gx; sum[idx] += v * w; wsum[idx] += w; seeds[idx] = 1;

return { originX, originY, cols: Math.ceil((maxX - originX) / cellSizeM) + padCells, rows: Math.ceil((maxY - originY) / cellSizeM) + padCells, };

} } }

} // ---- The splat --------------------------------------------------export function buildField(cells, cfg = FIELD_CONFIG) { const { cellSizeM, splatRadiusM, normalPower } = cfg; const { cols, rows, originX, originY } = gridExtentFor(cells, cfg); const n = cols * rows; const sum = new Float64Array(n); // weighted value total const wsum = new Float64Array(n); // weight total const seeds = new Uint8Array(n); // squares with a direct contribution

// ---- The isotropic half ---------------------------------------// Sum and weight are blurred separately, then divided. Blurring the // ratio lets a square with almost no weight pull as hard. const sigmaCells = (cfg.valueRadiusM - splatRadiusM) / (3 * cellSizeM); if (sigmaCells > 0.05) { const { taps, reach: gr } = gaussianTaps(sigmaCells); const scratch = new Float64Array(n); blurSeparable(sum, cols, rows, taps, gr, scratch); blurSeparable(wsum, cols, rows, taps, gr, scratch); }

const splat2 = splatRadiusM * splatRadiusM; const reach = Math.ceil(splatRadiusM / cellSizeM);

// ---- The claim boundary ---------------------------------------// Measured as a distance, not as a share of coverage: the weight // total grows with how many walls stand over a square. The seeds // carry the facing mask, so ground behind a wall clips sooner. const nearestM = distanceTransform(seeds, cols, rows) .map((d) => d * cellSizeM);

// Only a cell exactly on a square centre bypasses the facing mask. // Anything looser exempts the square behind the wall, which then // seeds the distance transform from inside the building. const nearM = 1e-6; for (let k = 0; k < cells.count; k++) { const v = cells.value[k]; if (!Number.isFinite(v)) continue; const px = cells.x[k]; const py = cells.y[k]; // The wall’s outward normal, used as a facing mask below. const fi = cells.facadeIndex[k]; const nx = cells.facadeNormal[fi * 2]; const ny = cells.facadeNormal[fi * 2 + 1]; const cx = Math.floor((px - originX) / cellSizeM);

APPENDIX

// ---- Resolve --------------------------------------------------// NaN means no data. It does not mean zero: zero is a real reading. const values = new Float32Array(n).fill(NaN); for (let i = 0; i < n; i++) { if (wsum[i] <= 0 || nearestM[i] > cfg.clipDistanceM) continue; values[i] = sum[i] / wsum[i]; } return { values, cols, rows, originX, originY, cellSizeM }; }

183


Appendix 04.11 : Zones.js Zones.js divides the ground field into value bands and traces each band as a closed polygon. The same polygon is filled, outlined and used for selection, so the shape on screen and the area being measured are identical. // ============================================================ // HEAT ZONES // Source: js/viewer/zones.js // ============================================================ // ---- Parameters -------------------------------------------------const CONTOUR_CONFIG = { selectableBands: 5, // bands the field is cut into method: ‘equal’, // ‘equal’ | ‘quantile’ hotBandFraction: 0.25, // widen the hottest band by this much chaikin: 3, // corner-cutting smoothing passes simplifyM: 0.02, // Douglas-Peucker tolerance, metres }; // ---- Band edges -------------------------------------------------// Returns the ascending thresholds separating the bands, from a // sorted array of the field’s finite values. export function thresholdsFor(sorted, cfg = CONTOUR_CONFIG) { const k = cfg.selectableBands; if (k === 1 || sorted.length === 0) return []; const out = cutsFor(sorted, k, cfg);

// ---- Tracing the bands ------------------------------------------export function buildZones(field, cfg = CONTOUR_CONFIG) { const { cols, rows, values, cellSizeM, originM } = field; const finite = [...values].filter(Number.isFinite).sort((a, b) => a b); if (!finite.length) return []; const thresholds = thresholdsFor(finite, cfg); const k = thresholds.length + 1; // The one place grid indices become metres. No half-cell term and // no sign flip: either one shifts or mirrors the whole map, and // nothing on screen looks wrong. const [originX, originY] = originM; const worldX = (g) => originX + g * cellSizeM; const worldY = (g) => originY + g * cellSizeM; // Smooth, then simplify. What comes out is THE polygon: filled, // outlined and clicked from this one array. const finish = (ring) => simplify(chaikin(ring, cfg.chaikin), cfg. simplifyM);

// Widened as a fraction of the local gap, so it means the same // across a 15 degC spread and a 1000 W/m2 one. if (cfg.hotBandFraction > 0 && out.length) { const last = out.length - 1; const below = last > 0 ? out[last - 1] : sorted[0]; out[last] = below + (out[last] - below) * (1 - cfg.hotBandFraction); } return out;

// The repeated closing vertex is dropped: rings are closed // implicitly here, and a duplicate makes the smoothing round a // corner that does not exist. Holes get the same passes. const toWorld = (ring) => finish( ring.slice(0, -1).map(([gx, gy]) => [worldX(gx), worldY(gy)]), ); // ---- One extraction per band, on its own membership -----------// Contouring “value >= threshold” nests the bands. Per-band // membership gives polygons that do not overlap and meet exactly. const zones = []; for (let b = 0; b < k; b++) { const member = new Float64Array(cols * rows); for (let i = 0; i < member.length; i++) { member[i] = Number.isFinite(values[i]) && bandOf(values[i], thresholds) === b ? 1 : 0; }

} function cutsFor(sorted, k, cfg) { if (cfg.method === ‘equal’) { // Equal interval: a zone describes an absolute band, so two // sites are comparable. const lo = sorted[0]; const hi = sorted[sorted.length - 1]; const step = (hi - lo) / k; return Array.from({ length: k - 1 }, (_, i) => lo + step * (i + 1)); } // Quantile: every zone holds the same number of squares. The cut is // taken at an index rather than interpolated, because the // classifier is `>` and the threshold has to be a value that // occurs. const out = []; for (let i = 1; i < k; i++) { const at = Math.ceil((sorted.length * i) / k) - 1; out.push(sorted[Math.min(sorted.length - 1, Math.max(0, at))]); } return out;

// The library pairs each hole with its parent ring, which is why // it is used rather than a hand-written marching squares pass. const polygons = []; for (const multi of d3contours().size([cols, rows]).thresholds([0.5])(member)) { for (const poly of multi.coordinates) { polygons.push({ outer: toWorld(poly[0]), holes: poly.slice(1).map(toWorld), }); } }

} // Which band a value falls in. Thresholds ascend; band 0 is coolest. function bandOf(value, thresholds) { let b = 0; while (b < thresholds.length && value > thresholds[b]) b++; return b; }

// Summed over squares, never integrated over the drawn polygon: // smoothing shrinks a ring slightly. zones.push({ band: b, polygons, stats: statsForBand(values, thresholds, b) }); } return zones; }

184

ALGORITHMIC COOLING


Appendix 04.12 : Contour.js Contour.js traces iso-lines through the ground field by marching squares and stitches the resulting segments into continuous paths, which become both the zone boundaries and the contour lines drawn over the terrain. It smooths

each outline into a readable curve and reduces its vertex count without changing its shape. It also decides whether a clicked point falls inside a polygon, so the shape drawn and the shape measured remain one geometry.

// ============================================================ // CONTOUR & POLYGON GEOMETRY // Source: js/viewer/contour.js // ============================================================

case 11: segments.push([R, T]); break; case 12: segments.push([L, R]); break; case 13: segments.push([B, R]); break; case 14: segments.push([L, B]); break;

// ---- Marching squares -------------------------------------------// Walks every 2x2 block of samples and emits the segments where the // iso-level crosses it. Vertices sit on the CENTRE lattice, half a // square in on both axes: the samples are square centres.

// Saddles: two diagonal corners above, two below. Split into // two segments rather than guessed at. case 5: segments.push([T, L], [B, R]); break; case 10: segments.push([L, B], [R, T]); break; }

function crossing(a, b, level) { return (level - a) / (b - a); }

} } return stitch(segments);

export function isoPaths(field, level, values = field.values) { const { cols, rows, cellSizeM } = field; const [originX, originY] = field.originM;

}

const wx = (gx) => originX + (gx + 0.5) * cellSizeM; const wy = (gy) => originY + (gy + 0.5) * cellSizeM;

// ---- Stitching --------------------------------------------------// Joins segments end to end into continuous paths. Open paths are // walked first, from the segments nothing leads into, so a line that // runs off the edge of the data is not read as a ring.

const segments = [];

const key = (p) => `${p[0]},${p[1]}`;

for (let r = 0; r < rows - 1; r++) { for (let c = 0; c < cols - 1; c++) { const v00 = values[r * cols + c]; const v10 = values[r * cols + c + 1]; const v11 = values[(r + 1) * cols + c + 1]; const v01 = values[(r + 1) * cols + c];

function stitch(segments) { const outgoing = new Map(); const incoming = new Set();

// SW sample // SE // NE // NW

// A block touching a square with no reading emits nothing, so // the line simply stops where the data does. if (!Number.isFinite(v00) || !Number.isFinite(v10) || !Number.isFinite(v11) || !Number.isFinite(v01)) continue; const idx = (v00 >= level ? 1 : 0) | (v10 >= level ? 2 : 0) | (v11 >= level ? 4 : 0) | (v01 >= level ? 8 : 0); if (idx === 0 || idx === 15) continue;

segments.forEach(([a, b], i) => { const k = key(a); if (!outgoing.has(k)) outgoing.set(k, []); outgoing.get(k).push(i); incoming.add(key(b)); }); const used = new Uint8Array(segments.length); const paths = [];

// wholly above or

const walk = (start) => { const points = [segments[start][0], segments[start][1]]; used[start] = 1;

below // The four edge crossings, each from its two corners in a FIXED // order: west to east, south to north. The neighbouring block // then produces an identical float, which is what lets them join. const B = [wx(c + crossing(v00, v10, level)), wy(r)]; const T = [wx(c + crossing(v01, v11, level)), wy(r + 1)]; const L = [wx(c), wy(r + crossing(v00, v01, level))]; const R = [wx(c + 1), wy(r + crossing(v10, v11, level))]; // Wound so the above-level side is on the left of travel: rings // run counter-clockwise around a high, so a hole is told from an // island by the sign of its area. switch (idx) { case 1: segments.push([B, L]); break; case 2: segments.push([R, B]); break; case 3: segments.push([R, L]); break; case 4: segments.push([T, R]); break; case 6: segments.push([T, B]); break; case 7: segments.push([T, L]); break; case 8: segments.push([L, T]); break; case 9: segments.push([B, T]); break;

APPENDIX

const head = key(segments[start][0]); let tail = key(segments[start][1]); let closed = false; for (;;) { if (tail === head) { closed = true; break; } const next = (outgoing.get(tail) ?? []).find((i) => !used[i]); if (next === undefined) break; used[next] = 1; points.push(segments[next][1]); tail = key(segments[next][1]); } // A closed path has repeated its first point as its last, dropped // here so the caller need not know which of the two it holds. if (closed) points.pop(); paths.push({ points, closed }); };

185


for (let i = 0; i < segments.length; i++) { if (!used[i] && !incoming.has(key(segments[i][0]))) walk(i); } for (let i = 0; i < segments.length; i++) { if (!used[i]) walk(i); }

const stack = [0, far, far, n]; while (stack.length) { const b = stack.pop(); const a = stack.pop(); if (b - a < 2) continue; const ax = ring[a % n][0]; const ay = ring[a % n][1]; const ex = ring[b % n][0] - ax; const ey = ring[b % n][1] - ay; const len2 = ex * ex + ey * ey;

return paths; } // ---- Parameters -------------------------------------------------const CONTOUR_CONFIG = { chaikin: 3, // corner-cutting passes simplifyM: 0.02, // Douglas-Peucker tolerance, metres };

let worst = -1; let worstD = -1; for (let i = a + 1; i < b; i++) { const px = ring[i % n][0] - ax; const py = ring[i % n][1] - ay; const cross = px * ey - py * ex; const d = len2 > 0 ? (cross * cross) / len2 : px * px + py * py; if (d > worstD) { worstD = d; worst = i; } }

// simplifyM must stay far below the ground grid’s cell size. // Douglas-Peucker can make a ring self-intersect, and a // self-intersecting polygon has no inside. 2 cm against 2 m. // ---- Smoothing --------------------------------------------------// Cuts every corner, twice per pass. Chaikin rather than a spline: a // spline overshoots where curvature is high and can cross itself. // It shrinks the curve, so every figure is summed over grid squares. export function chaikin(ring, iterations = 0) { if (ring.length < 3) return ring; let pts = ring; for (let it = 0; it < iterations; it++) { const n = pts.length; const out = new Array(n * 2); for (let i = 0; i < n; i++) { const [ax, ay] = pts[i]; const [bx, by] = pts[(i + 1) % n]; out[i * 2] = [ax + (bx - ax) * 0.25, ay + (by - ay) * 0.25]; out[i * 2 + 1] = [ax + (bx - ax) * 0.75, ay + (by - ay) * 0.75]; } pts = out; } return pts; } // ---- Simplification ---------------------------------------------// Runs AFTER the smoothing. Simplifying first hands the smoothing a // single long edge, and a quarter of it is cut off as a corner. export function simplify(ring, toleranceM = 0) { const n = ring.length; if (!(toleranceM > 0) || n < 4) return ring; // Two anchors, not one: on a closed ring the chord from a point to // itself has no direction, so the ring collapses. let far = 0; let farD = -1; for (let i = 1; i < n; i++) { const dx = ring[i][0] - ring[0][0]; const dy = ring[i][1] - ring[0][1]; const d = dx * dx + dy * dy; if (d > farD) { farD = d; far = i; } } const keep = new Uint8Array(n); keep[0] = 1; keep[far] = 1; const tol2 = toleranceM * toleranceM; // An explicit stack: the recursive form overflows on the rings that // need it most.

186

if (worstD > tol2) { keep[worst % n] = 1; stack.push(a, worst, worst, b); } } return ring.filter((_, i) => keep[i]); } // ---- The edge index ---------------------------------------------// The ray cast is O(vertices), asked about tens of thousands of points // against rings of tens of thousands: one click measured 16 s and 46 s. // A +x ray meets only edges straddling its y, so edges bucket by y. const RING_INDEX = new WeakMap(); // Below this a bucketed scan is slower than a flat one. Such a ring // still gets its bounding box. const INDEX_MIN_VERTICES = 64; function ringIndex(ring) { const cached = RING_INDEX.get(ring); if (cached !== undefined) return cached; const n = ring.length; let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity; for (let i = 0; i < n; i++) { x0 = Math.min(x0, ring[i][0]); x1 = Math.max(x1, ring[i][0]); y0 = Math.min(y0, ring[i][1]); y1 = Math.max(y1, ring[i][1]); } if (n < INDEX_MIN_VERTICES || !(y1 > y0)) { const flat = { x0, y0, x1, y1, nB: 0, start: null, edge: null, invH: 0 }; RING_INDEX.set(ring, flat); return flat; } const nB = Math.max(1, Math.min(4096, Math.ceil(n / 8))); const invH = nB / (y1 - y0); const bucketOf = (y) => { const b = Math.floor((y - y0) * invH); return b < 0 ? 0 : b >= nB ? nB - 1 : b; }; // Counting sort into compressed-sparse-row form, so the index is // two typed arrays rather than nB separate arrays. const start = new Int32Array(nB + 1);

ALGORITHMIC COOLING


for (let i = 0; i < n; i++) { const ay = ring[i][1]; const by = ring[(i + 1) % n][1]; if (ay === by) continue; // horizontal: never crosses for (let b = bucketOf(Math.min(ay, by)); b <= bucketOf(Math.max(ay, by)); b++) { start[b + 1]++; } } for (let b = 0; b < nB; b++) start[b + 1] += start[b]; const edge = new Int32Array(start[nB]); const fill = start.slice(0, nB); for (let i = 0; i < n; i++) { const ay = ring[i][1]; const by = ring[(i + 1) % n][1]; if (ay === by) continue; for (let b = bucketOf(Math.min(ay, by)); b <= bucketOf(Math.max(ay, by)); b++) { edge[fill[b]++] = i; } } const index = { x0, y0, x1, y1, invH, nB, start, edge }; RING_INDEX.set(ring, index); return index; }

for (const hole of polygon.holes) { if (pointInRing(hole, x, y)) return false; } return true; } // ---- Overlap ----------------------------------------------------// Strict signs on both orientation tests, so touching and collinear // overlap do not count. Adjacent bands share a boundary exactly. function segmentsCross(ax, ay, bx, by, cx, cy, dx, dy) { const d1 = (bx - ax) * (cy - ay) - (by - ay) * (cx - ax); const d2 = (bx - ax) * (dy - ay) - (by - ay) * (dx - ax); const d3 = (dx - cx) * (ay - cy) - (dy - cy) * (ax - cx); const d4 = (dx - cx) * (by - cy) - (dy - cy) * (bx - cx); return ((d1 > 0) !== (d2 > 0)) && ((d3 > 0) !== (d4 > 0)); } // Both halves are needed: one shape inside another has no boundary // crossing, and a bar laid across a band has every vertex outside the // other. The caller passes a rectangle, so the loop is 4n. export function polygonsOverlap(a, b) { for (const p of a.outer) if (pointInPolygon(b, p[0], p[1])) return true; for (const p of b.outer) if (pointInPolygon(a, p[0], p[1])) return true; const an = a.outer.length; const bn = b.outer.length; for (let i = 0; i < an; i++) { const [ax, ay] = a.outer[i]; const [bx, by] = a.outer[(i + 1) % an];

// ---- Hit testing ------------------------------------------------// Crossing number along a +x ray. The half-open edge test counts a // vertex sitting exactly on the ray once rather than twice. export function pointInRing(ring, x, y) { const ix = ringIndex(ring);

for (let m = 0; m < bn; m++) { const [cx, cy] = b.outer[m]; const [dx, dy] = b.outer[(m + 1) % bn]; if (segmentsCross(ax, ay, bx, by, cx, cy, dx, dy)) return true; }

// Outside the ring’s own box a ray meets either nothing or every // edge an even number of times. Either way the point is outside. if (x < ix.x0 || x > ix.x1 || y < ix.y0 || y > ix.y1) return false; const n = ring.length; let inside = false;

} return false; }

const crosses = (i) => { const [ax, ay] = ring[i]; const [bx, by] = ring[(i + 1) % n]; if ((ay > y) !== (by > y) && x < ((bx - ax) * (y - ay)) / (by - ay) + ax) { inside = !inside; } }; if (ix.nB === 0) { for (let i = 0; i < n; i++) crosses(i); return inside; } // Only the bucket holding this y can contain a crossing edge. let b = Math.floor((y - ix.y0) * ix.invH); b = b < 0 ? 0 : b >= ix.nB ? ix.nB - 1 : b; for (let k = ix.start[b]; k < ix.start[b + 1]; k++) crosses(ix. edge[k]); return inside; } // The outer ring, then every hole. A hole is a building footprint: // ground the field makes no claim about. export function pointInPolygon(polygon, x, y) { if (!pointInRing(polygon.outer, x, y)) return false;

APPENDIX

187


Turn static files into dynamic content formats.

Create a flipbook
Algorithmic Cooling (MSc) by Emergent Technologies and Design [EmTech] Selected Dissertations Repository - Issuu