Main Utilities package

CRS (Coordinate Reference System) utilities for DistrictHeatingSim.

Provides automatic CRS suggestion based on geographic location and a curated list of common projected coordinate systems.

author:

Dipl.-Ing. (FH) Jonas Pfeiffer

districtheatingsim.utilities.crs_utils.suggest_crs_from_location(lon: float, lat: float) str[source]

Suggest an appropriate projected CRS based on WGS84 coordinates.

For European locations (lon −6° to 36°, lat 35° to 72°) the function returns an ETRS89 UTM zone (EPSG:25832–25834). Outside Europe it returns the matching WGS84 UTM zone (EPSG:326xx / 327xx).

Parameters:
  • lon (float) – Longitude in decimal degrees (WGS84)

  • lat (float) – Latitude in decimal degrees (WGS84)

Returns:

EPSG code string, e.g. "EPSG:25833"

Return type:

str

districtheatingsim.utilities.crs_utils.epsg_from_urn(urn: str) str[source]

Convert an OGC URN CRS identifier to a plain EPSG code string.

Example: "urn:ogc:def:crs:EPSG::25833""EPSG:25833" If the input is already in "EPSG:XXXXX" form it is returned unchanged.

Parameters:

urn (str) – OGC URN or EPSG string

Returns:

EPSG code string

Return type:

str

districtheatingsim.utilities.crs_utils.crs_to_urn(crs: str) str[source]

Convert a plain EPSG code to the OGC URN format used in GeoJSON CRS objects.

Example: "EPSG:25833""urn:ogc:def:crs:EPSG::25833"

Parameters:

crs (str) – EPSG code string (e.g. "EPSG:25833")

Returns:

OGC URN string

Return type:

str

Column contracts for app-owned CSV files (BACKLOG D4 step 4).

CSV files here are user- and Excel-editable, so — unlike the JSON artifacts in districtheatingsim.utilities.schema — the column header is the contract; a version field would break pandas/Excel interop. Instead we centralize the required columns per file kind and validate on load, turning a KeyError raised deep inside the maths (data["VLT_max"] …) into one clear message naming every missing column up front. Generalizes the ad-hoc UTM_X/UTM_Y checks.

GUI-free and pandas-free at import (the DataFrame is duck-typed via .columns).

author:

Dipl.-Ing. (FH) Jonas Pfeiffer

districtheatingsim.utilities.csv_schemas.CSV_SCHEMAS: dict[str, dict[str, tuple[str, ...]]] = {'building': {'optional': ('Heizgrenztemperatur', 'Heizexponent', 'P_max'), 'required': ('Wärmebedarf', 'Gebäudetyp', 'Subtyp', 'WW_Anteil', 'Normaußentemperatur', 'VLT_max', 'RLT_max', 'Steigung_Heizkurve')}, 'coordinates': {'optional': (), 'required': ('UTM_X', 'UTM_Y')}}

Required (and known-optional) columns per CSV kind. optional is documentation only — it lists columns the readers use when present but tolerate when absent.

districtheatingsim.utilities.csv_schemas.required_columns(kind: str) tuple[str, ...][source]

Return the required column names for a CSV kind.

districtheatingsim.utilities.csv_schemas.validate_csv_columns(df, kind: str) None[source]

Raise KeyError if df is missing any required column for kind.

Parameters:
  • df – A loaded table (duck-typed: needs a .columns collection).

  • kind – A key registered in CSV_SCHEMAS.

Raises:

KeyError – Naming every missing required column (and listing the present ones), so a renamed/missing header is a clear up-front error rather than an opaque failure deep in the calculation.

Path utility functions for development and frozen builds.

This module provides functions to locate data directories correctly in both development and PyInstaller frozen builds.

author:

Dipl.-Ing. (FH) Jonas Pfeiffer

districtheatingsim.utilities.path_utils.get_data_path(subfolder='')[source]

Get path to data directory for both development and frozen builds.

Parameters:

subfolder (str) – Optional subfolder within data directory

Returns:

Absolute path to data directory or subfolder

Return type:

str

Note

In frozen builds, data folder is located next to the executable for user accessibility.

districtheatingsim.utilities.path_utils.get_project_data_path(project_name='')[source]

Get path to project_data directory for both development and frozen builds.

Parameters:

project_name (str) – Optional name of specific project

Returns:

Absolute path to project_data directory or specific project

Return type:

str

Note

In frozen builds, project_data folder is located next to the executable.

districtheatingsim.utilities.path_utils.get_internal_data_path(relative_path)[source]

Get path to data inside _internal folder (not user-accessible).

Parameters:

relative_path (str) – Relative path within internal data structure

Returns:

Absolute path to internal data

Return type:

str

districtheatingsim.utilities.path_utils.is_frozen()[source]

Check if running as frozen (compiled) application.

Returns:

True if running as compiled executable, False otherwise

Return type:

bool

districtheatingsim.utilities.path_utils.get_app_root()[source]

Get application root directory.

Returns:

Path to executable directory (frozen) or project root (development)

Return type:

str

Versioned-JSON helpers for app-owned project artifacts (BACKLOG D4).

A single home for the “version + migrate” bookkeeping that D2 duplicated across project_settings.json and the EnergySystem JSON. New writes carry a _meta block holding the schema version (drives migration) and the app version (diagnostics only). Reads tolerate three on-disk forms so older files keep loading:

  • new: {"_meta": {"schema_version": N, "app_version": "x.y.z"}, …}

  • legacy: {"version": N, …} — the D2 top-level field

  • pre-versioning: neither present → schema version 0

Deliberately GUI-free and dependency-light (stdlib only) so the domain core (heat_generators) can use it without dragging in PyQt6 (BACKLOG B5).

author:

Dipl.-Ing. (FH) Jonas Pfeiffer

districtheatingsim.utilities.schema.META_KEY = '_meta'

Key under which the metadata block is stored in a serialized artifact.

districtheatingsim.utilities.schema.SCHEMA_VERSIONS: dict[str, int] = {'building_data': 1, 'dialog_config': 1, 'energy_system': 1, 'project_settings': 1}

Registry of every versioned artifact kind → its current schema version. Bump a value here (and add a migration step in the artifact’s loader) when its on-disk format changes. This is the single source of truth that replaces the scattered *_VERSION constants.

districtheatingsim.utilities.schema.current_version(kind: str) int[source]

Return the current schema version registered for kind.

districtheatingsim.utilities.schema.schema_version_of(raw: dict) int[source]

Extract the schema version from a loaded dict, tolerating all on-disk forms.

Parameters:

raw – The dict as loaded from JSON.

Returns:

_meta.schema_version if present, else the legacy top-level version, else 0 (pre-versioning).

Return type:

int

districtheatingsim.utilities.schema.add_meta(data: dict, kind: str) dict[source]

Return a copy of data stamped with a _meta block for kind.

Drops any legacy top-level version field so a re-saved file uses the new form exclusively.

Parameters:
  • data – The payload to serialize.

  • kind – A key registered in SCHEMA_VERSIONS.

Returns:

data plus a _meta block (schema + app version).

Return type:

dict

districtheatingsim.utilities.schema.check_version(raw: dict, kind: str) int[source]

Read the schema version of a loaded artifact and warn if it is too new.

A file written by a newer app may use a format this version cannot fully understand; we log a warning and let the caller load best-effort. (Migration of older files stays per-artifact, since the steps differ.)

Parameters:
  • raw – The dict as loaded from JSON.

  • kind – A key registered in SCHEMA_VERSIONS.

Returns:

The schema version found on disk (0 = pre-versioning).

Return type:

int

Test Reference Year (TRY) import module for German weather data.

This module provides functionality to import and parse standardized meteorological data files used for building energy simulations and district heating calculations.

author:

Dipl.-Ing. (FH) Jonas Pfeiffer

districtheatingsim.utilities.test_reference_year.import_TRY(filename)[source]

Read and parse TRY (Test Reference Year) weather data file.

Parameters:

filename (str) – Path to TRY file in fixed-width format

Returns:

Tuple of (temperature, windspeed, direct_radiation, global_radiation, cloud_cover)

Return type:

tuple of numpy.ndarray

Raises:

Note

  • File contains 8760 hourly values for a complete year

  • Temperature in °C (at 2m height)

  • Wind speed in m/s (at 10m height)

  • Radiation values in W/m² (horizontal surface)

  • Cloud cover in eighths (0-8, where 9=not observable)

  • Global radiation is calculated as sum of direct and diffuse radiation

Utility functions for the DistrictHeatingSim application.

This module provides helper functions for resource path resolution, global exception handling, and theme management.

author:

Dipl.-Ing. (FH) Jonas Pfeiffer

districtheatingsim.utilities.utilities.get_resource_path(relative_path)[source]

Resolve the absolute path to a resource file for development, PyInstaller, or pip-installed package.

Parameters:

relative_path (str) – Relative path to the resource from the package root

Returns:

Absolute path to the resource file

Return type:

str

Notes

  • In development, returns the path relative to the source tree.

  • In PyInstaller builds, handles data folders outside _internal.

  • In pip installations, uses importlib.resources for package data.

districtheatingsim.utilities.utilities.handle_global_exception(exc_type, exc_value, exc_traceback)[source]

Global exception handler that displays errors in a QMessageBox dialog.

Parameters:

Note

KeyboardInterrupt exceptions are handled by the default system handler.

districtheatingsim.utilities.utilities.get_stylesheet_based_on_time()[source]

Get stylesheet identifier based on current system time.

Returns:

‘light_theme_style_path’ if between 6:00-18:00, otherwise ‘dark_theme_style_path’

Return type:

str

Note

Light theme is applied during daytime (6 AM - 6 PM), dark theme during evening/night hours.