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
compile_epw(): high-level one-call compiler.read_epw(): load an AMY or TMY into pandas.EPWConfig: compilation configuration.StationMeta: station metadata container.Smhi2EpwError: common expected-error boundary.
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)
- station_id
Explicit SMHI MetObs station identifier. If omitted,
latitudeandlongitudelocate 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;
countryis 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:
- 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.
- 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:
- 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.
Nonedisables 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:
- gap_fallback_max_distance_km
Positive donor radius about the requested point; default 75 km.
- Type:
- gap_fallback_max_stations
Positive total candidate-attempt limit; default three stations.
- Type:
- weather_policy
"automatic"(default) recovers same-year weather with ERA5 and warnings;"strict"retains explicit source and gap failures.- Type:
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)
- station
Meteorological station supplying observations;
Nonewhen station metadata is unavailable and requested coordinates enable reanalysis.- Type:
- coordinate_distance_km
Distance from the station to the requested point, or
Nonewhen no station metadata is available.- Type:
float | None
- report
Detailed filling, solar-source, cloud, and energy-closure diagnostics.
- 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:
- 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_epwLoad 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 withnumpy.nan. Set this toFalsewhen 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 asframe.attrs['header'],frame.attrs['location'], andframe.attrs['source_path'].- Return type:
- 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.
nameis used for output folders;citydefaults to that name in the EPW header. Supply either a SMHIstation_idor 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
- 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. Commoncompiler_optionsaccept 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:
- 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:
locations (Sequence[WeatherLocation]) – Same inputs as
plan_amy_batch().years (Sequence[int]) – Same inputs as
plan_amy_batch().output_dir (str | Path) – Same inputs as
plan_amy_batch().compiler_options (Mapping[str, Any] | None) – Same inputs as
plan_amy_batch().morphing (sequence of MorphConfig, optional) – At most one configuration per climate family; empty means AMYs only.
- Returns:
Completed diagnostics and paths. Returned lists can be edited without changing previously written JSON receipts.
- Return type:
- 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 (list[CompileResult])
morph_results (list[MorphResult])
manifest_path (str)
- amy_results
Existing compiler diagnostics, one per completed baseline.
- Type:
- morph_results
Artifact and scenario references, one per completed future EPW.
- Type:
list of MorphResult
Examples
>>> from smhi2epw import BatchResult >>> result = BatchResult([], [], "weather/manifest.json") >>> result.summary()["future_count"] 0
- 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. Emptyscenarios,periodsormodelsselect all supported values. Models are combined into an ensemble by FWG.versionoverrides 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',)
- 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 namedSOURCE_SCENARIO_PERIOD.epwwith JSON receipts and optional FWG STAT companions. Existing destinations are rejected. Missing outputs and malformed EPWs raiseMorphingErrororValidationError; 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.
- source_path, output_path, provenance_path
Baseline EPW, future EPW and JSON receipt paths, respectively.
- Type:
Examples
>>> from smhi2epw import MorphResult >>> result = MorphResult("base.epw", "future.epw", "ssp245", 2050, ... "future.epw.json") >>> result.summary()["period"] 2050
- class smhi2epw.MorphingError[source]
Bases:
Smhi2EpwErrorReport 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:
- latitude, longitude
Station coordinates in decimal degrees.
- distance_km(lat, lon)[source]
Calculate great-circle distance to a target coordinate.
- Parameters:
- Returns:
Haversine distance in kilometres, using mean Earth radius 6371.0088 km.
- Return type:
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.
- clamped_dni_hours
Hours whose positive DNI was reduced by horizon or extraterrestrial limits. Routine nighttime zeros are not counted.
- Type:
- 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:
- cloud_available
Whether usable observed or reconstructed total cloud cover was available.
- Type:
- solar_source
One of
"strang","measured+strang_partition","strang_ghi+erbs","measured+erbs","era5", or"mixed"for solar assembled from different hourly sources.- Type:
- linear_filled_hours, diurnal_filled_hours
Filled-hour counts by column and method.
- bounded_filled_hours
Reconstructed hours clipped to each variable’s representable range.
- 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.
- 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:
- warnings
Structured records containing
code,messageand optionalvariable/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.
- reanalysis_metadata
Provider, model, grid/elevation, attribution and original overlap comparisons; pressure differences are expressed in Pa.
- Type:
- source_fractions
Source proportions by variable over exported LST hours.
Exceptions
- class smhi2epw.Smhi2EpwError[source]
Bases:
ExceptionBase 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:
Smhi2EpwErrorReport 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:
Smhi2EpwErrorReport 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:
Smhi2EpwErrorReport 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.