Public API reference

The symbols below form the supported application-facing interface.

Compile SMHI open data into EnergyPlus Weather Actual Meteorological Years.

The top-level namespace contains the stable entry points needed by most users. Lower-level ingestion, processing, solar, and export modules remain available for teaching and advanced quality-control workflows.

Public API

Examples

>>> from smhi2epw import EPWConfig, compile_epw, read_epw
>>> config = EPWConfig(2023, "gothenburg.epw", station_id=71420)
>>> result = compile_epw(config)
>>> weather = read_epw(result.output_path)

Compiler

class smhi2epw.EPWConfig(year, output_path, station_id=None, city='Unknown', region='SE', country='SWE', utc_offset=1.0, cache_dir='.smhi_cache', max_workers=8, latitude=None, longitude=None, refresh=False, cache_ttl=None, radiation_station_id=None, radiation_station_auto=True, radiation_station_max_distance_km=50.0, target_elevation_m=None, provenance_path=None, metobs_gap_fallback=False, gap_fallback_max_distance_km=75.0, gap_fallback_max_stations=3, weather_policy='automatic')[source]

Describe one Actual Meteorological Year compilation.

Parameters:
  • year (int)

  • output_path (str)

  • station_id (int | None)

  • city (str)

  • region (str)

  • country (str)

  • utc_offset (float)

  • cache_dir (str | None)

  • max_workers (int)

  • latitude (float | None)

  • longitude (float | None)

  • refresh (bool)

  • cache_ttl (float | None)

  • radiation_station_id (int | None)

  • radiation_station_auto (bool)

  • radiation_station_max_distance_km (float | None)

  • target_elevation_m (float | None)

  • provenance_path (str | None)

  • metobs_gap_fallback (bool)

  • gap_fallback_max_distance_km (float)

  • gap_fallback_max_stations (int)

  • weather_policy (str)

year

Completed calendar year to compile, from 1999 onward.

Type:

int

output_path

Destination EPW path. Its parent directory must already exist.

Type:

str

station_id

Explicit SMHI MetObs station identifier. If omitted, latitude and longitude locate a station. Automatic policy permits partial coverage or reanalysis-only recovery when metadata is unavailable.

Type:

int | None

city, region, country

Human-readable EPW location fields. They must not contain commas or newlines; country is normally an ISO-style code such as "SWE".

utc_offset

Whole-hour offset from UTC to Local Standard Time. Daylight saving is intentionally ignored. Nordic locations normally use 1.0.

Type:

float

cache_dir

Directory for raw API responses, or None to disable caching.

Type:

str | None

max_workers

Positive number of concurrent parameter requests.

Type:

int

latitude, longitude

Optional requested coordinates in decimal degrees. When supplied, they control STRÅNG and ERA5 queries, solar geometry, and EPW location even if an explicit meteorological station is used.

refresh

Ignore otherwise valid cached responses when True.

Type:

bool

cache_ttl

Maximum cache age in seconds, or None for no age limit.

Type:

float | None

radiation_station_id

Explicit SMHI Sol station for measured GHI. An unusable station fails in strict policy; automatic policy warns and uses other sources.

Type:

int | None

radiation_station_auto

Discover a nearby full-year Sol station when no explicit ID is given.

Type:

bool

target_elevation_m

Target height above sea level in metres. Defaults to station elevation. Used for both the EPW header and derived atmospheric station pressure.

Type:

float | None

radiation_station_max_distance_km

Maximum automatic Sol-station distance in kilometres. None disables the radius; the default is 50 km.

Type:

float | None

provenance_path

Separate JSON receipt with source, response and output hashes. Automatic policy defaults to output_path + ".json".

Type:

str | None

metobs_gap_fallback

Enable assessed nearby donors in strict policy; default False. Automatic policy always evaluates donors before reanalysis.

Type:

bool

gap_fallback_max_distance_km

Positive donor radius about the requested point; default 75 km.

Type:

float

gap_fallback_max_stations

Positive total candidate-attempt limit; default three stations.

Type:

int

weather_policy

"automatic" (default) recovers same-year weather with ERA5 and warnings; "strict" retains explicit source and gap failures.

Type:

str

Examples

Compile by station ID while evaluating solar radiation at the requested city-centre coordinates:

config = EPWConfig(
    year=2023,
    output_path="gothenburg_2023.epw",
    station_id=71420,
    city="Gothenburg",
    latitude=57.7156,
    longitude=11.9924,
)

Notes

Configuration is a plain dataclass. Validation occurs in compile_epw(), before the first network request.

class smhi2epw.compiler.CompileResult(output_path, rows, station, interpolated_fraction, coordinate_distance_km, report, radiation_station_id=None, radiation_station_distance_km=None, target_latitude=None, target_longitude=None, target_elevation_m=None, pressure_method='smhi_qff_inverse_v1')[source]

Summarize a completed compilation and its quality diagnostics.

Parameters:
  • output_path (str)

  • rows (int)

  • station (StationMeta | None)

  • interpolated_fraction (float)

  • coordinate_distance_km (float | None)

  • report (ProcessingReport)

  • radiation_station_id (int | None)

  • radiation_station_distance_km (float | None)

  • target_latitude (float | None)

  • target_longitude (float | None)

  • target_elevation_m (float | None)

  • pressure_method (str)

output_path

Path of the validated EPW file.

Type:

str

rows

Number of hourly rows written: 8760 or 8784.

Type:

int

station

Meteorological station supplying observations; None when station metadata is unavailable and requested coordinates enable reanalysis.

Type:

smhi2epw.ingestion.StationMeta | None

interpolated_fraction

Mean fraction of samples filled across processed input columns.

Type:

float

coordinate_distance_km

Distance from the station to the requested point, or None when no station metadata is available.

Type:

float | None

report

Detailed filling, solar-source, cloud, and energy-closure diagnostics.

Type:

smhi2epw.processing.ProcessingReport

radiation_station_id

Selected Sol station identifier, if measured GHI was requested.

Type:

int | None

radiation_station_distance_km

Distance from that Sol station to the requested point, in kilometres.

Type:

float | None

Examples

The result is intended to be inspected rather than ignored:

result = compile_epw(config)  # doctest: +SKIP
print(result.rows, result.report.solar_source)  # doctest: +SKIP
smhi2epw.compile_epw(config, client=None, *, log_context=None)[source]

Compile one year of SMHI weather into a validated EPW file.

Parameters:
  • config (EPWConfig) – Location, year, cache, station-selection, and output settings.

  • client (CachedClient | None) – Optional HTTP/cache client. Supplying a compatible test double makes the complete pipeline deterministic and offline.

Returns:

Output location, station choices, interpolation metrics, and solar quality diagnostics.

Return type:

CompileResult

Raises:
  • IngestionError – If configuration, station coverage, HTTP access, or source payloads are invalid.

  • DataGapError – If strict source requirements fail or automatic recovery cannot produce physically representable complete same-year inputs.

  • ValidationError – If the processed year cannot be represented as a strict EPW file.

Notes

Requested coordinates and station coordinates have different roles. The requested point drives STRÅNG, solar geometry, and the EPW header; the selected MetObs station supplies observed weather. Target elevation defaults to the station height. Parameter 9 is sea-level pressure; surface pressure is estimated at the target using the inverse SMHI QFF formula.

Automatic policy evaluates bounded temporal filling and nearby donors, then uses same-year ERA5 for remaining gaps. Surface pressure from ERA5 bypasses SMHI’s QFF conversion. The automatic result includes structured warnings and defaults to a separate output_path + ".json" receipt.

The output is replaced atomically only after all 35 fields and all 8760/8784 rows pass validation. A receipt filesystem/serialization failure warns and returns the valid EPW under automatic policy.

Examples

>>> from smhi2epw import EPWConfig, compile_epw
>>> config = EPWConfig(2023, "gothenburg.epw", station_id=71420)
>>> result = compile_epw(config)
>>> result.rows
8760

See also

smhi2epw.read_epw

Load the generated file for analysis.

Reader

smhi2epw.read_epw(path, *, validate=True, missing_as_nan=True, log_context=None)[source]

Read an AMY or TMY EPW file into a labelled data frame.

Parameters:
  • path (str | PathLike[str]) – Path to an EnergyPlus Weather file.

  • validate (bool) – If True, require eight standard headers, 35 fields per row, 8760 or 8784 ordered hourly data rows, possible integer calendar fields, consistent minutes of 0 or 60, and valid physical ranges.

  • missing_as_nan (bool) – If True, replace each field’s EnergyPlus missing sentinel with numpy.nan. Set this to False when inspecting the raw encoding.

Returns:

The 35 EPW fields under EPW_COLUMNS. EPW calendar columns are preserved rather than converted to an index because TMY files may use different representative years for different months. The original headers, parsed location metadata, and source path are available as frame.attrs['header'], frame.attrs['location'], and frame.attrs['source_path'].

Return type:

pandas.DataFrame

Raises:

ValidationError – If the file cannot be decoded as a structurally valid EPW file.

Notes

EPW hours are numbered 1 through 24 and describe the interval ending at that hour. Thus hour 1 represents 00:00–01:00 and hour 24 represents 23:00–24:00 in local standard time.

Examples

>>> from smhi2epw import read_epw
>>> weather = read_epw("gothenburg_2023.epw")
>>> weather[["dry_bulb", "ghi"]].describe()
>>> weather.attrs["location"]["city"]
'Gothenburg'
smhi2epw.EPW_COLUMNS = ('year', 'month', 'day', 'hour', 'minute', 'data_source_and_uncertainty_flags', 'dry_bulb', 'dew_point', 'relative_humidity', 'pressure', 'extraterrestrial_horizontal', 'extraterrestrial_direct_normal', 'horizontal_ir', 'ghi', 'dni', 'dhi', 'global_horizontal_illuminance', 'direct_normal_illuminance', 'diffuse_horizontal_illuminance', 'zenith_luminance', 'wind_direction', 'wind_speed', 'total_sky_cover', 'opaque_sky_cover', 'visibility', 'ceiling_height', 'present_weather_observation', 'present_weather_codes', 'precipitable_water', 'aerosol_optical_depth', 'snow_depth', 'days_since_last_snowfall', 'albedo', 'liquid_precipitation_depth', 'liquid_precipitation_quantity')

Built-in immutable sequence.

If no argument is given, the constructor returns an empty tuple. If iterable is specified the tuple is initialized from iterable’s items.

If the argument is a tuple, the return value is the same object.

Weather batches and morphing

class smhi2epw.WeatherLocation(name, station_id=None, latitude=None, longitude=None, city=None, region='SE', country='SWE', utc_offset=1.0, target_elevation_m=None)[source]

Describe a batch location with a unique filesystem-safe identifier.

name is used for output folders; city defaults to that name in the EPW header. Supply either a SMHI station_id or both coordinates. Explicit coordinates retain the single-file compiler’s target semantics.

Parameters:
  • name (str) – Unique output identifier using ASCII letters, digits, underscores or hyphens.

  • station_id (int, optional) – Positive SMHI meteorological station identifier.

  • latitude (float, optional) – Target WGS84 coordinates in decimal degrees, supplied together.

  • longitude (float, optional) – Target WGS84 coordinates in decimal degrees, supplied together.

  • city (str, optional) – EPW location labels. City defaults to name; region/country to SE/SWE.

  • region (str, optional) – EPW location labels. City defaults to name; region/country to SE/SWE.

  • country (str, optional) – EPW location labels. City defaults to name; region/country to SE/SWE.

  • utc_offset (float, default 1) – Whole-hour local standard time offset, without daylight saving time.

  • target_elevation_m (float, optional) – Target elevation above sea level in metres.

Examples

>>> from smhi2epw import WeatherLocation
>>> location = WeatherLocation("gothenburg", station_id=71420)
>>> location.summary()["station_id"]
71420
summary()[source]

Copy all supplied location metadata without looking up a station.

Return type:

dict

smhi2epw.plan_amy_batch(locations, years, output_dir, *, compiler_options=None)[source]

Validate every location/year and return compiler jobs without I/O.

Output paths are OUTPUT/LOCATION/YEAR/LOCATION_YEAR.epw. Common compiler_options accept EPWConfig’s cache, recovery and solar settings; location, year, output and provenance fields belong to the batch planner. Duplicate locations and years are errors, preventing output collisions.

Parameters:
  • locations (sequence of WeatherLocation) – Explicit station or coordinate selections. No objects are modified.

  • years (sequence of int) – Completed source calendar years from 1999 onward.

  • output_dir (str or Path) – Destination root, relative to the current working directory.

  • compiler_options (mapping, optional) – Common EPWConfig recovery, radiation, cache and worker settings.

Returns:

Validated configurations in location order, then year order.

Return type:

list of EPWConfig

Raises:

ValidationError, IngestionError – If selections, names or compiler settings are invalid.

Examples

>>> from smhi2epw import WeatherLocation, plan_amy_batch
>>> jobs = plan_amy_batch([WeatherLocation("gbg", station_id=71420)],
...                       [2022, 2023], "weather")
>>> [job.year for job in jobs]
[2022, 2023]
smhi2epw.compile_amy_batch(locations, years, output_dir, *, morphing=(), compiler_options=None, log_context=None)[source]

Compile each location/year and morph each AMY with every climate family.

All configurations and optional runtime prerequisites are checked before provider access. Runs are sequential; individual compilations retain their own concurrent provider requests. Existing outputs are rejected. The manifest is updated after each completed stage, and records a failed run without discarding earlier valid outputs. Reruns need a fresh output root.

Parameters:
Returns:

Completed diagnostics and paths. Returned lists can be edited without changing previously written JSON receipts.

Return type:

BatchResult

Raises:
  • Smhi2EpwError – If planning, acquisition, validation or morphing fails.

  • OSError – If output directories or progress receipts cannot be written.

Notes

Explicitly contacts SMHI and potentially Open-Meteo, writes files and, when morphing is supplied, starts Java. No study scheduling or resume is provided. Multi-file publication is not transactional.

Examples

This live example needs provider access and a new output directory:

from smhi2epw import WeatherLocation, compile_amy_batch
result = compile_amy_batch(
    [WeatherLocation("gbg", station_id=71420)], [2022, 2023], "weather"
)
assert len(result.amy_results) == 2
class smhi2epw.BatchResult(amy_results, morph_results, manifest_path)[source]

Collect completed AMY diagnostics, future files and the batch manifest.

Parameters:
amy_results

Existing compiler diagnostics, one per completed baseline.

Type:

list of CompileResult

morph_results

Artifact and scenario references, one per completed future EPW.

Type:

list of MorphResult

manifest_path

JSON progress inventory path. Inspection never opens it.

Type:

str

Examples

>>> from smhi2epw import BatchResult
>>> result = BatchResult([], [], "weather/manifest.json")
>>> result.summary()["future_count"]
0
summary()[source]

Describe completed outputs using already loaded artifact references.

Return type:

dict

class smhi2epw.MorphConfig(fwg_jar_path, family='ssp', scenarios=(), periods=(), models=(), version=None)[source]

Select a climate family, scenarios, periods, models and FWG executable.

family='ssp' requires the global JAR; family='rcp' requires the Europe JAR. Empty scenarios, periods or models select all supported values. Models are combined into an ensemble by FWG. version overrides detection from the JAR filename (global: 3, 4 or 5; Europe: 1, 2 or 3). Urban heat island adjustment is disabled; other scientific settings use pyfwg defaults. Java must be available on PATH.

Parameters:
  • fwg_jar_path (str) – Explicit FWG JAR; relative paths use the working directory.

  • family (str, default 'ssp') – Global SSP or European RCP climate projections.

  • scenarios (tuple of str, optional) – Supported scenario identifiers for the selected family.

  • periods (tuple of int, optional) – Climate period labels 2050 and/or 2080, separate from source years.

  • models (tuple of str, optional) – pyfwg GCM names or European GCM-RCM pairs to ensemble.

  • version (str, optional) – Major FWG version override when not present in the JAR filename.

Examples

Construct and inspect selections without accessing a JAR or Java:

>>> from smhi2epw import MorphConfig
>>> config = MorphConfig("FutureWeatherGenerator_v4.0.2.jar",
...                      scenarios=("ssp245",), periods=(2050,))
>>> config.summary()["scenarios"]
('ssp245',)
summary()[source]

Copy configured selections without resolving executable dependencies.

Return type:

dict

smhi2epw.morph_epw(source_path, output_dir, config, *, log_context=None)[source]

Morph one AMY or TMY into selected future climate scenarios.

Requires smhi2epw[morphing], Java and the appropriate FWG JAR. Outputs are named SOURCE_SCENARIO_PERIOD.epw with JSON receipts and optional FWG STAT companions. Existing destinations are rejected. Missing outputs and malformed EPWs raise MorphingError or ValidationError; pyfwg can otherwise silently return an empty or incomplete file list.

FWG runs once per input. Current engines receive scenario/period selections; legacy versions compute their full scenario set before output filtering. All requested outputs are checked before any are published.

Parameters:
  • source_path (str or Path) – Existing complete-year EPW; never changed. Relative to the working directory.

  • output_dir (str or Path) – Explicit destination, created when needed.

  • config (MorphConfig) – Family, executable, ensemble and selection settings.

Returns:

References in selected scenario order, then period order.

Return type:

list of MorphResult

Raises:
  • MorphingError – If dependencies, Java execution or requested outputs are unavailable.

  • ValidationError – If selections or EPW structure/ranges are invalid, or outputs exist.

  • OSError – If prerequisite files or directories cannot be read or created.

Notes

Reads input weather/JARs, starts Java and writes EPW/JSON/optional STAT artifacts. No provider weather is acquired by this operation. Publication refuses concurrent overwrites; several files are not a transaction. A disk failure can leave earlier complete files. Choose a fresh directory to rerun.

Examples

After providing a real baseline, Java and global FWG JAR:

from smhi2epw import MorphConfig, morph_epw
outputs = morph_epw(
    "baseline.epw", "future",
    MorphConfig("FutureWeatherGenerator_v4.0.2.jar",
                scenarios=("ssp245",), periods=(2050,)),
)
assert outputs[0].scenario == "ssp245"
class smhi2epw.MorphResult(source_path, output_path, scenario, period, provenance_path)[source]

Locate a morphed weather file and its auditable climate receipt.

Parameters:
  • source_path (str)

  • output_path (str)

  • scenario (str)

  • period (int)

  • provenance_path (str)

source_path, output_path, provenance_path

Baseline EPW, future EPW and JSON receipt paths, respectively.

Type:

str

scenario

Selected SSP or RCP identifier.

Type:

str

period

Future climate period label, independent of the source calendar.

Type:

int

Examples

>>> from smhi2epw import MorphResult
>>> result = MorphResult("base.epw", "future.epw", "ssp245", 2050,
...                      "future.epw.json")
>>> result.summary()["period"]
2050
summary()[source]

Copy artifact references without opening weather files or receipts.

Return type:

dict

class smhi2epw.MorphingError[source]

Bases: Smhi2EpwError

Report unavailable morphing dependencies or failed climate generation.

Station and diagnostics

class smhi2epw.StationMeta(station_id, name, latitude, longitude, elevation=0.0, wmo_id='999999')[source]

Describe the MetObs station supplying observed weather.

Parameters:
station_id

Positive SMHI station identifier.

Type:

int

name

Human-readable station name with API instruction text removed.

Type:

str

latitude, longitude

Station coordinates in decimal degrees.

elevation

Station height in metres above sea level.

Type:

float

wmo_id

Genuine WMO identifier, or "999999" when SMHI supplies none.

Type:

str

distance_km(lat, lon)[source]

Calculate great-circle distance to a target coordinate.

Parameters:
  • lat (float) – Target latitude and longitude in decimal degrees.

  • lon (float) – Target latitude and longitude in decimal degrees.

Returns:

Haversine distance in kilometres, using mean Earth radius 6371.0088 km.

Return type:

float

Examples

>>> station = StationMeta(71420, "Göteborg A", 57.7156, 11.9924)
>>> station.distance_km(57.7156, 11.9924)
0.0
class smhi2epw.processing.ProcessingReport(interpolated_fraction=<factory>, total_interpolated_fraction=0.0, clamped_dni_hours=0, energy_balance_max_residual=0.0, missing_columns=<factory>, cloud_available=False, solar_source='strang', linear_filled_hours=<factory>, diurnal_filled_hours=<factory>, max_gap_hours=<factory>, bounded_filled_hours=<factory>, invalid_observation_hours=<factory>, primary_missing_hours=<factory>, cross_station_filled_hours=<factory>, gap_fallback_sources=<factory>, gap_fallback_attempts=<factory>, required_reconstructed_fraction=0.0, warnings=<factory>, reanalysis_filled_hours=<factory>, reanalysis_metadata=<factory>, source_fractions=<factory>, weather_classification='observation_based')[source]

Record data filling and solar-quality diagnostics.

Parameters:
interpolated_fraction

Original missing fraction for each processed source column.

Type:

Dict[str, float]

total_interpolated_fraction

Mean of the per-column missing fractions.

Type:

float

clamped_dni_hours

Hours whose positive DNI was reduced by horizon or extraterrestrial limits. Routine nighttime zeros are not counted.

Type:

int

energy_balance_max_residual

Maximum absolute interval residual of GHI - (DHI + dirh) in W/m². Mean DNI times a midpoint cosine need not equal mean horizontal beam.

Type:

float

missing_columns

Optional source columns that were absent or entirely missing.

Type:

List[str]

cloud_available

Whether usable observed or reconstructed total cloud cover was available.

Type:

bool

solar_source

One of "strang", "measured+strang_partition", "strang_ghi+erbs", "measured+erbs", "era5", or "mixed" for solar assembled from different hourly sources.

Type:

str

linear_filled_hours, diurnal_filled_hours

Filled-hour counts by column and method.

max_gap_hours

Longest gap before temporal filling, after any donor recovery.

Type:

Dict[str, int]

bounded_filled_hours

Reconstructed hours clipped to each variable’s representable range.

Type:

Dict[str, int]

primary_missing_hours, invalid_observation_hours

Required-variable missing and invalid counts before source recovery.

cross_station_filled_hours

Required-variable counts filled from same-hour donor observations.

Type:

Dict[str, int]

gap_fallback_sources, gap_fallback_attempts

Donor receipts and attempted requests, including parameter errors.

required_reconstructed_fraction

Pre-recovery missing/invalid fraction across required ingestion cells. Populated by automatic or strict donor recovery.

Type:

float

warnings

Structured records containing code, message and optional variable/details; plausibility warnings retain valid extremes.

Type:

List[dict]

reanalysis_filled_hours

Weather-variable sample counts supplied by ERA5 on the buffered grid, including optional cloud cover during actual weather replacement hours.

Type:

Dict[str, int]

reanalysis_metadata

Provider, model, grid/elevation, attribution and original overlap comparisons; pressure differences are expressed in Pa.

Type:

dict

source_fractions

Source proportions by variable over exported LST hours.

Type:

Dict[str, Dict[str, float]]

weather_classification

"observation_based", "mixed_reconstructed" or "reanalysis_only". Includes reconstructed GHI; routine physical nighttime zeros do not downgrade otherwise observation-based inputs.

Type:

str

Exceptions

class smhi2epw.Smhi2EpwError[source]

Bases: Exception

Base class for expected, user-facing package failures.

Catch this exception when an application wants one boundary for ingestion, gap, and output-validation failures while allowing programming errors to propagate normally.

class smhi2epw.IngestionError[source]

Bases: Smhi2EpwError

Report invalid configuration, unavailable data, or malformed API input.

This exception covers failures that occur before scientific processing, including HTTP errors, corrupt cached payloads, station-coverage failures, unsupported years, and invalid coordinates or UTC offsets.

class smhi2epw.DataGapError[source]

Bases: Smhi2EpwError

Report required weather that remains missing after permitted recovery.

Temporal reconstruction remains limited to 48 hours. Automatic weather policy can fill longer gaps with assessed observations or same-year reanalysis; strict policy retains errors when its permitted sources cannot supply the required hours. Neither policy fabricates a successful file when every available source is incomplete.

class smhi2epw.ValidationError[source]

Bases: Smhi2EpwError

Report a structural, range, or filesystem EPW validation failure.

Examples include an incorrect header order, a row with other than 35 fields, a partial year, physically invalid required values, or failure to atomically replace the destination file.