Skip to content

Releases: justinfmccarty/pyepwmorph

v3.6.0

Choose a tag to compare

@justinfmccarty justinfmccarty released this 27 Oct 12:06

See CHANGELOG.md.

v3.5.0

Choose a tag to compare

@justinfmccarty justinfmccarty released this 12 Oct 15:43

Radiation morphs change: diffuse horizontal and direct normal now keep the
EPW's own split, and EPWs without extraterrestrial radiation morph correctly.
Global horizontal radiation and every other variable are unchanged.

Fixed

  • No direct normal from EPWs with empty extraterrestrial columns. The
    radiation morph read exthorrad_Whm2 for the clearness index and capped
    direct normal at extdirrad_Whm2. weather-file-builder up to 2.3.0 wrote
    both as 0 in ERA5 typical and extreme years, so every Radiation or Clouds
    and Radiation morph of such a file came out diffuse only, with direct
    normal 0 in every hour. When a column holds no positive value it is now
    computed from the solar position (new procedures.extraterrestrial_or_computed,
    solar.extraterrestrial_radiation) and a warning is logged. The computed
    columns are also written to the morphed EPW (rounded, 0 at night) and named
    in COMMENTS 2. Filled columns are used and written as they are. calc_dirnor also falls back to the solar constant
    when its ceiling column is empty.

Changed

  • Diffuse and direct normal keep the EPW's split (procedures.morph_radiation_split).
    Before, both were recalculated from scratch with the Ridley et al. (2010)
    model, which differs from the model the EPW was split with (weather-file-builder
    uses DIRINT). That moved diffuse and direct normal by about 5% even with no
    climate signal (an ERA5 TMY at Zurich: diffuse -5%, direct normal +5%), and
    the error went into every future file. Now the diffuse fraction is the EPW's
    own plus the change the Ridley model predicts between present and morphed
    global radiation, bounded so it never passes the model's future value, and
    direct normal scales the EPW's own value by the change in horizontal beam
    (beam change projected mid-hour where the present beam is under 10 W/m2).
    With no climate signal both are now returned unchanged, and the identity
    tests require it. Zurich ERA5 TMY, CH2025 GWL 3.0 median (global +2.0%):
    diffuse -1.3%, direct normal +4.3% (3.4.0 with the columns filled: -7.7%
    and +10.4%).
  • Radiation solar geometry is taken mid-hour. EPW rows are hour-ending
    and the dataframe index marks the start of each hour; the radiation
    procedures took the sun's position at that start, 30 minutes early. They
    now use the middle (solar_geometry(..., offset_minutes=HOUR_MIDPOINT_MINUTES)).
    The returned index and the EPW's date and time columns are unchanged.
  • calc_difhor and calc_dirnor remain for a full re-split but the morph no
    longer calls them.

v3.4.0

Choose a tag to compare

@justinfmccarty justinfmccarty released this 09 Oct 12:09

See CHANGELOG.md.

v3.3.0

Choose a tag to compare

@justinfmccarty justinfmccarty released this 09 Oct 09:48

See CHANGELOG.md.

v3.2.0

Choose a tag to compare

@justinfmccarty justinfmccarty released this 08 Oct 08:18

See CHANGELOG.md.

v3.1.0

Choose a tag to compare

@justinfmccarty justinfmccarty released this 08 Oct 07:31

See CHANGELOG.md.

v3.0.0

Choose a tag to compare

@justinfmccarty justinfmccarty released this 22 Sep 12:42

This release corrects several morphing calculations. Morphed humidity, dew
point, wind speed, cloud cover, and direct and diffuse radiation all change
,
so files produced by earlier versions should be regenerated. Dry bulb
temperature, pressure, and global horizontal radiation are unaffected.

Fixed

  • Relative humidity was inflated even with no climate signal. morph_relhum
    evaluated the psychrometer equation at the dry bulb temperature instead of the
    wet bulb temperature, which overstated vapour pressure. Morphing an EPW with an
    unchanged specific humidity raised relative humidity by a median of 21% and
    pushed hundreds of hours to saturation. The conversion now goes through the
    humidity ratio directly and round-trips exactly.
  • The humidity climate signal was almost entirely discarded.
    utilities.relative_delta returns a ratio, but morph_relhum treated it as a
    percentage twice over, turning a 20% change in specific humidity into 1%. A
    +20% and a -20% projection produced identical output. The full ratio is now
    applied.
  • The wind climate signal was almost entirely discarded. morph_wspd had the
    same ratio-as-percentage bug: a 20% modelled increase in wind speed morphed to
    1.2%.
  • Direct normal irradiance could reach physically impossible values.
    calc_dirnor divided the horizontal beam component by the sine of the solar
    altitude with no lower bound, producing values up to 62,000 W/m2 near the
    horizon. Hours below a 2 degree solar altitude are now zeroed and the result is
    capped at the extraterrestrial direct normal irradiance recorded in the EPW.
  • Cloud cover changes below 10 percentage points vanished. calc_tsc
    truncated the shift to an integer before applying it, so a 9 percentage point
    change in cloud fraction became zero tenths. The shift is now carried as a float
    and rounded once, at the end.
  • Diffuse horizontal irradiance is bounded. The Ridley diffuse fraction is
    clipped to [0, 1] and the result can no longer exceed global horizontal.
  • morph_relhum now returns a DatetimeIndex like every other procedure, instead
    of a RangeIndex.
  • Appending to the COMMENTS 2 header no longer raises on EPW files that do not
    carry that line; it is created before DATA PERIODS when missing.
  • The CMIP6 cache key now includes the time_slices argument, so a custom
    temporal slice no longer silently returns data cut to the default bounds.
  • utilities.ts_8760 respects the year argument when a timezone is supplied; it
    previously hard-coded 2022.
  • access.build_accessible_data_list returned None; it now returns the list of
    source IDs.

Changed

  • Dependencies of a requested variable are now written to the output file.
    Previously, asking for Humidity alone computed a morphed dry bulb temperature
    internally but discarded it, while asking for Dew Point alone wrote it. Every
    resolved dependency is now written, which keeps the morphed EPW internally
    consistent. MorphConfig.resolved_variables exposes the full ordered list.
  • Solar geometry uses a fixed UTC offset taken from the EPW LOCATION line
    and the year of the EPW data. It previously looked up a named IANA timezone,
    which injected daylight saving shifts into local solar time that the weather
    data does not contain, and hard-coded three different years.
  • procedures.calc_dirnor signature changed. The unused present_dirnor
    argument was removed and extraterrestrial_dirnor and min_solar_altitude
    were added:
    calc_dirnor(morphed_glohor, morphed_difhor, longitude, latitude, utc_offset, extraterrestrial_dirnor=None, min_solar_altitude=2.0)
  • procedures.calc_osc returns integer tenths, matching calc_tsc and the EPW
    field definition, instead of floats.
  • The CMIP6 cache moved from the system temp directory to the per-user cache
    directory, so it survives a reboot and is not world-readable on shared hosts.
    The default cap rose from 50 MB to 500 MB. PYEPWMORPH_CACHE_DIR and
    PYEPWMORPH_CACHE_MAX_MB override both.
  • Cache lookups moved from coordinate.coordinate_cmip6_data into
    workflow.compile_climate_model_data, so a cache hit no longer opens the
    remote catalogue first. Calling coordinate_cmip6_data directly always
    recomputes.
  • cache.CACHE_DIR and cache.CACHE_MAX_SIZE_MB were replaced by
    cache.get_cache_dir() and cache.get_cache_max_size_mb(), which read the
    environment on each call.
  • The morphing procedures are vectorised. The per-row DataFrame.apply calls
    were replaced with numpy broadcasting, which cuts the radiation chain from
    roughly 1.1 s to a few milliseconds per morph.
  • Library modules no longer call warnings.filterwarnings("ignore") at import
    time, which used to silence warnings for the whole host process.
  • The cache and utility modules log instead of printing.
  • Minimum pandas raised to 2.2, which is the real floor for the "ME" and
    "h" resample aliases already in use.

Removed

  • pyepwmorph.tools.ladybug_psychrometrics, which was copied from an
    AGPL-3.0 project into an MIT-licensed package. It is replaced by
    pyepwmorph.tools.psychrometrics, a vectorised implementation of the same
    ASHRAE Handbook (2017) formulas following the MIT-licensed PsychroLib
    reference.
  • Unused dependencies: meteocalc, skyfield, ipython, lz4, distributed,
    and timezonefinder.

Added

  • pyepwmorph.tools.psychrometrics with vectorised saturation vapour pressure,
    humidity ratio, relative humidity, specific humidity, and dew point functions.
  • configuration.resolve_variable_order, which expands variable dependencies
    transitively and returns them in a safe morphing order.
  • Epw.add_comment, which appends to COMMENTS 2 and creates the header in the
    correct position when it is absent.
  • utilities.month_factors, utilities.day_factors, and utilities.as_array
    for broadcasting monthly and daily climatologies onto an hourly index.
  • solar.fixed_offset for building a daylight-saving-free timezone from an EPW
    UTC offset.
  • morphing_workflow accepts time_slices and forwards it to the CMIP6 fetch.
  • A continuous integration workflow running ruff and the test suite on Python
    3.9 through 3.13.
  • The test suite grew from 42 to 104 tests, including an identity-morph suite
    that asserts an unchanged climate leaves the EPW unchanged for every variable.
    That suite alone catches all five numerical bugs fixed in this release.

v2.2.0

Choose a tag to compare

@justinfmccarty justinfmccarty released this 07 Mar 21:24

What's new

See README for full breaking changes list.

v2.1.1

Choose a tag to compare

@justinfmccarty justinfmccarty released this 07 Mar 20:48

What's new

See README for full breaking changes list.

v2.1.0

Choose a tag to compare

@justinfmccarty justinfmccarty released this 07 Mar 20:30

What's new in v2.1.0

See README for full breaking changes list.