# Outputs

This guide explains the output files generated by SOLWEIG-GPU and how to interpret and visualize the results.

## Output Structure

After running a simulation, outputs are saved in the `output_folder/` directory within your `base_path`. To write outputs elsewhere, set `base_path` to the desired directory and pass complete paths for the input rasters (Building DSM, DEM, Trees, land cover); see [Configuration](configuration.md#base_path). The structure is organized by tile key (origin coordinates in the raster grid):

```
base_path/
└── output_folder/
    ├── 0_0/
    │   ├── UTCI_0_0.tif
    │   ├── TMRT_0_0.tif
    │   └── SVF_0_0.tif
    ├── 0_1000/
    │   ├── UTCI_0_1000.tif
    │   ├── TMRT_0_1000.tif
    │   └── SVF_0_1000.tif
    └── 1000_0/
        ├── UTCI_1000_0.tif
        ├── TMRT_1000_0.tif
        └── SVF_1000_0.tif
```

Each subfolder is named by the tile key (e.g., `0_0`, `0_1000`, `1000_0`). File names use `TMRT` (not Tmrt) to match the written rasters.

## Output Files

### Universal Thermal Climate Index (UTCI)

**Filename:** `UTCI_X_Y.tif`  
**Format:** Multi-band GeoTIFF  
**Units:** °C  
**Description:** The Universal Thermal Climate Index, representing the "feels like" temperature.

UTCI is always computed and saved. It provides a comprehensive measure of thermal comfort that accounts for air temperature, mean radiant temperature, wind speed, and humidity.

**Interpretation:**

| UTCI Range (°C) | Thermal Stress Category |
|----------------|------------------------|
| > 46 | Extreme heat stress |
| 38 to 46 | Very strong heat stress |
| 32 to 38 | Strong heat stress |
| 26 to 32 | Moderate heat stress |
| 9 to 26 | No thermal stress |
| 0 to 9 | Slight cold stress |
| -13 to 0 | Moderate cold stress |
| -27 to -13 | Strong cold stress |
| -40 to -27 | Very strong cold stress |
| < -40 | Extreme cold stress |


### Mean Radiant Temperature (Tmrt)

**Filename:** `TMRT_X_Y.tif`  
**Format:** Multi-band GeoTIFF  
**Units:** °C  
**Description:** The mean radiant temperature in a standing position.

Tmrt represents the uniform temperature of an imaginary enclosure in which the radiant heat exchange with the human body equals the radiant heat exchange in the actual environment.

**Saved when:** `save_tmrt=True`

### Sky View Factor (SVF)

**Filename:** `SVF_X_Y.tif` (single-band; X_Y is the tile key)  
**Format:** Single-band GeoTIFF  
**Units:** Dimensionless (0-1)  
**Description:** The fraction of the sky hemisphere visible from each point.

SVF is a geometric parameter that quantifies the openness of a location to the sky. It affects both shortwave and longwave radiation exchange.

**Saved when:** `save_svf=True`

!!! Note:
    Unlike other outputs, SVF is a geometric property that doesn't change with time. It is saved as a single-band raster, not multi-band.

### Downwelling Shortwave (Kdown)

**Filename:** `Kdown_X_Y.tif`  
**Format:** Multi-band GeoTIFF  
**Units:** W/m²  
**Description:** Incoming shortwave (solar) radiation at the surface.

**Saved when:** `save_kdown=True`

### Upwelling Shortwave (Kup)

**Filename:** `Kup_X_Y.tif`  
**Format:** Multi-band GeoTIFF  
**Units:** W/m²  
**Description:** Reflected shortwave radiation from surfaces.

**Saved when:** `save_kup=True`

### Downwelling Longwave (Ldown)

**Filename:** `Ldown_X_Y.tif`  
**Format:** Multi-band GeoTIFF  
**Units:** W/m²  
**Description:** Incoming longwave (thermal) radiation.

**Saved when:** `save_ldown=True`

### Upwelling Longwave (Lup)

**Filename:** `Lup_X_Y.tif`  
**Format:** Multi-band GeoTIFF  
**Units:** W/m²  
**Description:** Outgoing longwave radiation from the surface.

**Saved when:** `save_lup=True`

### Shadow Maps

**Filename:** `Shadow_X_Y.tif`  
**Format:** Multi-band GeoTIFF  
**Units:** unitless (varies from 0 to 1)
**Description:** Shadow/sunlit classification for each pixel.

**Saved when:** `save_shadow=True`

### Wet Bulb Globe Temperature (WBGT) — New in Version 2

**Filename:** `WBGT_X_Y.tif`  
**Format:** Multi-band GeoTIFF  
**Units:** °C  
**Description:** The Wet Bulb Globe Temperature, a heat stress index widely used in occupational health and sports medicine. It is computed from the wet bulb temperature, black globe temperature (derived from Tmrt), and air temperature.

**Saved when:** `save_wbgt=True`

### Air Temperature (Ta) — New in Version 2

**Filename:** `Ta_X_Y.tif`  
**Format:** Multi-band GeoTIFF  
**Units:** °C  
**Description:** Diagnostic 2-m air temperature field used in the UTCI/WBGT calculation. When `use_uhi=True` with ERA5 forcing, this includes the diagnostic urban heat island intensity (UHII) adjustment.

**Saved when:** `save_ta=True`

### Wind Speed — New in Version 2

**Filename:** `Wind_X_Y.tif`  
**Format:** Multi-band GeoTIFF  
**Units:** m/s  
**Description:** Diagnostic 10-m wind speed field used in the UTCI calculation. When directional wind-extension coefficients are used (`ERA_5_z0_find=True` or `windcoeff_folder`), the wind field reflects the direction-dependent attenuation by buildings and vegetation.

**Saved when:** `save_wind=True`

!!! note "Urban heat island intensity (UHII)"
    When `use_uhi=True` with ERA5 forcing, a diagnostic UHII (GLIDE-SOL scheme) is written into the generated metfiles during preprocessing and added to the air temperature in the UTCI/WBGT calculation.

## Multi-Band Structure

Most outputs (except SVF) are saved as multi-band GeoTIFFs, where each band represents one hour of the simulation.

**Example:** For a 24-hour simulation starting at 00:00:

- Band 1: Hour 0 (00:00)
- Band 2: Hour 1 (01:00)
- Band 3: Hour 2 (02:00)
- ...
- Band 24: Hour 23 (23:00)

## Visualizing Outputs

### Using QGIS

1. **Open QGIS** and add the GeoTIFF file
2. **Multi-band rasters** will appear with all bands listed
3. **Select a specific band** to visualize a particular hour
4. **Apply color ramp** for better visualization:
   - For UTCI/Tmrt: Use a thermal color ramp (blue-red)
   - For SVF: Use a grayscale or inverted grayscale
   - For radiation: Use a sequential color ramp

!!! tip "Temporal Animation"
    In QGIS, you can use the Temporal Controller to animate the multi-band raster and see how UTCI changes throughout the day.

### Using Python

```python
from osgeo import gdal
import matplotlib.pyplot as plt
import numpy as np

# Open the UTCI file
ds = gdal.Open('output_folder/0_0/UTCI_0_0.tif')

# Read a specific hour (e.g., hour 12 = noon)
band = ds.GetRasterBand(12)
utci = band.ReadAsArray()

# Plot
plt.figure(figsize=(10, 8))
plt.imshow(utci, cmap='RdYlBu_r', vmin=20, vmax=45)
plt.colorbar(label='UTCI (°C)')
plt.title('UTCI at Noon')
plt.axis('off')
plt.tight_layout()
plt.savefig('utci_noon.png', dpi=300)
plt.show()
```

### Using ArcGIS

1. **Add the GeoTIFF** to your map
2. **Access band properties** through the raster properties dialog
3. **Create a mosaic** if you have multiple tiles
4. **Apply symbology** using the Symbology pane
5. **Export maps** for publication or presentation

## Merging Tiles

If your simulation generated multiple tiles, you may want to merge them into a single raster for easier visualization and analysis.

### UTCI tile merging example

```python
import os
import glob
import numpy as np
from tempfile import TemporaryDirectory
from osgeo import gdal

base_dir = r"path_to_base/output_folder"  # Locate the simulation output (base_path/output_folder)
pattern  = os.path.join(base_dir, "**", "UTCI*.tif") # Merging UTCI but this works for other variables as well
inputs   = glob.glob(pattern, recursive=True)
assert inputs, "No input tiles found!"

ds0 = gdal.Open(inputs[0])
n_bands = ds0.RasterCount
ds0 = None

out_dir = r"output_folder/UTCI" # Provide the folder where the merged files should be saved
os.makedirs(out_dir, exist_ok=True)

with TemporaryDirectory() as tmpdir:
    for b in range(1, n_bands + 1):
        print(f"Merging band {b}/{n_bands}")

        vrt_path = os.path.join(tmpdir, f"band{b:02d}.vrt")
        vrt_opts = gdal.BuildVRTOptions(
            bandList=[b],          # <- pick this band only
            srcNodata=-999,
            VRTNodata=np.nan       # nodata in the VRT
        )
        vrt_ds = gdal.BuildVRT(vrt_path, inputs, options=vrt_opts)
        if vrt_ds is None:
            raise RuntimeError(f"Failed to build VRT for band {b}")
        vrt_ds = None  # flush to disk

        out_tif = os.path.join(out_dir, f"merged_band{b:02d}_900.tif")
        tr_opts = gdal.TranslateOptions(
            format="GTiff",
            outputType=gdal.GDT_Float32,
            noData=np.nan,
            creationOptions=[
                "TILED=YES"  
            ]
        )
        gdal.Translate(out_tif, vrt_path, options=tr_opts)
```

## Data Analysis

### Computing Statistics

```python
import numpy as np
from osgeo import gdal

# Open UTCI file
ds = gdal.Open('output_folder/0_0/UTCI_0_0.tif')

# Compute statistics for each hour
for hour in range(1, ds.RasterCount + 1):
    band = ds.GetRasterBand(hour)
    utci = band.ReadAsArray()
    
    print(f"Hour {hour-1}:")
    print(f"  Mean UTCI: {np.mean(utci):.1f}°C")
    print(f"  Max UTCI: {np.max(utci):.1f}°C")
    print(f"  Min UTCI: {np.min(utci):.1f}°C")
    print(f"  Std UTCI: {np.std(utci):.1f}°C")
```

### Extracting Time Series

```python
import numpy as np
from osgeo import gdal

# Open UTCI file
ds = gdal.Open('output_folder/0_0/UTCI_0_0.tif')

# Define a point of interest (pixel coordinates)
x, y = 500, 500

# Extract time series
utci_timeseries = []
for hour in range(1, ds.RasterCount + 1):
    band = ds.GetRasterBand(hour)
    utci = band.ReadAsArray()
    utci_timeseries.append(utci[y, x])

# Plot time series
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 4))
plt.plot(range(24), utci_timeseries, marker='o')
plt.xlabel('Hour of Day')
plt.ylabel('UTCI (°C)')
plt.title('UTCI Time Series at Point (500, 500)')
plt.grid(True)
plt.tight_layout()
plt.savefig('utci_timeseries.png', dpi=300)
plt.show()
```
