Release Notes#
This page documents all changes to PyWAsP across releases. PyWAsP follows semantic versioning: breaking changes increment the major version, new features increment the minor version, and bug fixes increment the patch version. Changes that can break existing code, including those a minor release makes to functions and classes marked as experimental, are listed under Breaking changes.
Changelog#
All major changes are listed here.
2.1.0 (2026-10-01)#
PyWAsP 2.1 contains breaking changes, and many results change. Read Upgrading from 2.0 before you upgrade.
Highlights#
WAsP 12.10 defaults: PyWAsP reproduces WAsP 12.10 with its default settings and is tested against WAsP 12.10 results.
Obstacles:
TopographyMapaccepts anobstacle_mapof polygons with a height and an optional porosity, such as buildings or tree rows, andget_site_effectsreturns the shelter they give.More accurate wind farm AEP:
potential_aepandwind_farm_flow_mapintegrate gross AEP and wind speeds over the Weibull distribution and reproduce the WAsP PARK2 reference results to 1e-4–1e-5 relative accuracy. PARK1 and several flow map errors are fixed.Wind directions relative to grid north:
align_direction_crs,wwc_rotateandtswc_rotaterotate wind climates between direction frames. The downscale and predict functions rotate from the wind climate’s frame to the output points, and thegeneralize*functions can rotate to true north.No side effects on import:
import pywaspneither downloads data nor contacts the license server. The newpywasp mesoclimatecommand downloads the global mesoclimate files, and the license is checked at the first licensed calculation.Faster: Many calculations run faster than in 2.0.
macOS on Apple Silicon: Experimental conda packages for
osx-arm64are now available.
Upgrading from 2.0#
Most code runs unchanged, but many results change. Check the following:
Requirements: PyWAsP 2.1 needs Python 3.12 or later and windkit 2.2, which has breaking changes of its own; read its Upgrading from 2.1.
Reproducing 2.0 results: pass
gen_heights=[10, 25, 50, 100, 250]togeneralizeand setconf.climate[111] = 1 / 3on yourConfig.Mesoclimate files: seed them with
pywasp mesoclimate download(orpywasp.download_mesoclimate()) instead ofpython -c 'import pywasp'. Catchpywasp.MesoclimateMissingErrorwhere you caughtEOFErrororFileNotFoundErrorfrom the air density and mesoclimate functions.Errors: catch
pywasp.PywaspErrorfor bad input topotential_aep,wind_farm_flow_mapandgross_aep: a wind climate missing a required variable, an air density missing everywhere, awind_turbinesof the wrong length, an unknownair_density_correction, or aws_upper_limitthat leaves nothing to simulate.Elevation rasters with NaN: fill them with
windkit.fill_elevation_nodatabefore constructing aTopographyMap, and catchPywaspErrorinstead ofValueError. Re-save a.topofile that holds such a raster.Output shapes: a scalar input gives a scalar output, and an input with a scalar
heightcoordinate, such as araster, keeps it. PyWAsP 2.0 added a size-onepointorheightdimension. Compare results by dimension name, not position.Mesoclimates: select a single height of a multi-height mesoclimate before a Wind Atlas calculation, or use
pointdata withheight(point). A supplied mesoclimate, and thez0mesoandslfmesoof the site effects, must not differ between points at the same horizontal location.AEP totals and deficits: a yearly total is missing when any of its sectors is. To keep the 2.0
gross_aeptotal, useds["gross_aep_sector"].sum("sector", skipna=True, min_count=1). To keep the 2.0 all-sector deficits, usexr.where(ds["gross_aep_sector"] == 0.0, 0.0, ds["wdfreq"] * ds["potential_aep_deficit_sector"]).sum("sector", skipna=False), and the same withwspd_sectorandwspd_deficit_sector.Missing air density: a location whose
air_densityis NaN gets no AEP. Fill the air density in, pass theair_densityargument, or useair_density_correction="none".Net AEP:
net_aepcompounds losses, so net AEP from a loss table with more than one loss is slightly higher than in 2.0.Removed arguments and outputs: drop the
shearargument ofpotential_aepandwind_farm_flow_map(pass the later arguments ofwind_farm_flow_mapby keyword), selections on themodecoordinate of their results, theierrorvariable ofget_return_wind, which raisesCoreErrorinstead, andengine="fortran"ininterpolate_gwc.Meridian convergence: a
meridian_convergencevariable in a binned wind climate is ignored. For generalized wind climates downloaded from the Global Wind Atlas, or made with earlier PyWAsP versions, read the migration guide in tutorial 9.
New features#
TopographyMapaccepts anobstacle_mapof polygons with aheightcolumn and an optionalporositycolumn (default 0).get_site_effectsthen returns the shelter from these obstacles inobstacle_speedups; locations inside an obstacle and below its height get NaN, with a warning.saveandloadkeep the obstacle map, andget_site_effects_roseraises when one is set.Added
align_direction_crs, which rotates the wind directions of a TSWC, BWC, WWC or GWC between coordinate reference systems. The source frame comes fromsource_wind_dir_crsor thewind_dir_crsattribute.Added
wwc_rotateandtswc_rotate, which rotate a Weibull or time series wind climate by a given angle.The
generalize*functions gainedrotate_to_true_north(defaultFalse), which rotates wind directions to true north with the site’s meridian convergence. The downscale and predict functions gainedalign_direction_crs(defaultTrue), which rotates from the GWC’s direction frame to the output points.bwc_from_tswc(..., wind_dir_crs=...)rotates true-north directions to the grid north of a projected CRS before binning, unless the TSWC’swind_dir_crsalready names that CRS. The generalize and predict functions readwind_dir_crs, warn when it is absent, and reject a BWC with a geographic direction frame.Added the
pywasp mesoclimate download,statusandpathcommands, andpywasp.download_mesoclimate(),pywasp.mesoclimate_status()andpywasp.mesoclimate_path(), which download, list and locate the global mesoclimate files.predict_bwc,predict_bwc_from_site_effectsanddownscale_from_geostrophic_and_site_effects_to_bwcgainedn_wsbins_out(default 100), the number of bins in the output wind speed histogram, andallow_truncation, which turns the error for a truncated histogram into a warning and requiresadd_met=False.potential_aepandwind_farm_flow_mapwarn when the simulated wind speeds stop short of where the turbine still produces, usually becausews_upper_limitis too low.potential_aepandwind_farm_flow_mapno longer needturbulence_intensityfor the built-in wind farm models ("PARK1","PARK2_onshore"and"PARK2_offshore"), which don’t use it. The effective turbulence intensity outputs are then left out.The Wind Atlas functions accept a scalar
mesoclimate, such asget_climate(...).isel(point=0), and amesoclimatewith one point per horizontal location, in the order the locations first appear.get_spec_corr_facacceptspoint,stacked_point,scalarandsingle_pointtime series, not onlycuboid.baroclinicity_histogramgainedpercentile, the wind speed percentile used for finalization.New exceptions
pywasp.MesoclimateMissingError,LicenseConfigError,LicenseServerUnreachableErrorandPointsLimitError.Experimental conda packages for macOS on Apple Silicon (
osx-arm64).
Bug fixes#
Gross AEP from
potential_aepandwind_farm_flow_mapwas integrated over the simulated wind speed bins, which smeared the turbine’s cut-in and cut-out. Yearly totals were 0.06 % high at the defaultws_stepsize, sectors were off by up to 1.2 %, and wake losses were inflated by about 4 % of their value. Potential AEP is unchanged.Waked AEP misplaced power curve transitions where an upwind turbine cutting in or out makes the effective wind speed non-monotonic, shifting sector AEP by up to about 0.3 %.
wspd,wspd_effandturbulence_intensity_efffrompotential_aepandwind_farm_flow_mapdrifted withws_stepsizeandws_upper_limit. They are integrated over the Weibull distribution like the AEPs, sowspdis the Weibull mean.potential_aepwithwind_farm_model="PARK1"reported roughly a third of the AEP; it now lands within 0.2 % of PARK2 on a site total. PARK1 also runs withn_cpu_pywakegreater than 1.An even
n_subsectorcrashed. Withn_subsector > 1andsite_interp_method="linear", a subsector took its speed-up and turbulence intensity from a neighbouring sector instead of its parent sector.wind_farm_flow_maprotated the whole wake field half a sector away from the wind rose at the default settings.wind_farm_flow_mapgave an output point halfway between two wind climate points the wind speeds of one and the Weibull parameters of the other.site_interp_methodandsite_interp_boundsnow apply to the wind climate too.wind_farm_flow_mapwithair_density_correction="infer"corrected one power curve to the site’s mean air density, so itsgross_aepdiffered fromgross_aepby up to 2 %. Each output point’s power curve is now corrected to its own air density.wind_farm_flow_mapmapped a farm of several turbine models as if all were one of them; it now raisesPywaspError, so usepotential_aepfor a mixed farm. Withair_density_correction="infer"it used the first model inwtginstead of the onewind_turbines.wtg_keynames.wind_farm_flow_mapno longer addsturbulence_intensityto the wind climate it is given. An explicitturbulence_intensitynow replaces the wind climate’s inpotential_aepandwind_farm_flow_map, as their warning said.A location whose
air_densityis NaN had its power curve corrected to the last density in the WTG file, reporting an AEP about 8 % too high. Its AEP is now missing, with a warning, and a flow map leaves such cells out of its mean density.PywaspErroris raised when no location has an air density.A sector with a Weibull
Aof 0 contributes nothing to the AEP and wind speeds, instead of making the whole location undefined. A negativeAor a non-positivekmarks the sector as missing instead of raising, and a very peaked distribution no longer overflows.potential_aep_deficit_sectoris defined for a sector of zero frequency.gross_aepwithair_density_correction="none"no longer needs or reads the air density.gross_aep(..., use_sectors=False)raisedAlignmentErrorforscalar,stacked_pointandcuboidwind climates.Invalid input to
potential_aep,wind_farm_flow_mapandgross_aepraises aPywaspErrornaming the problem (TypeErrorfor awtgof the wrong type), instead ofAttributeError,KeyError,UnboundLocalErroror an error inside py_wake.gross_aepreturned results for only as many locations as there were turbines.net_aepandpx_aepresults carry their own metadata instead of that ofpotential_aepandnet_aep, andnet_aepupdateshistory.estimate_sensitivity_factorleaves out locations with a missing sector or zero gross AEP instead of returning an undefined factor, and raisesPywaspErrorif no location is left.predict_bwc,predict_bwc_from_site_effectsanddownscale_from_geostrophic_and_site_effects_to_bwcsilently dropped wind speeds beyond the output histogram, which could also corrupt memory; they now raise. With a non-defaultn_gbinsthe histogram was too short, so sectors did not sum to 1.Wind Atlas downscaling with
interp_method="nearest","linear"or"natural"raises when the interpolated GWC does not line up with the sites, instead of using it at the wrong points.The Wind Atlas functions accept a mesoclimate with a size-one
heightdimension.Climate generalization, downscaling and prediction no longer add
flow_sep_heightto the displacement a second time. Results with the released configurations, where it is 0, are unchanged.predict_wwcandpredict_wwc_from_site_effectssized the input heights by the number of output points, which could crash the WAsP core.interpolate_gwctreats a GWC with one horizontal location and several heights as a single point, keeping its heights and taking the nearest source height for each target, where non-nearest methods failed. It keeps global attributes such aswind_dir_crs.interpolate_gwcfailed whenoutput_locshas noheightdimension, as apointstructure, a single location or arasterwith a scalarheightdoes.interpolate_gwcmixed the heights of apointGWC that has the same heights at every location (with"linear","cubic"or"natural"), and of a multi-heightstacked_pointGWC with"natural", without a warning. Each source height is now interpolated on its own. Apointsource with several heights at some locations but not the same heights everywhere raisesPywaspError.get_climatereturned wrong or NaN values for locations that span the ±180° dateline together with points far from it.Weibull fits could bias
kfor histograms whose bins are not 1 m/s wide and whose sector mean lies within about one bin of 1 m/s.wwc_rotateraisedValueErrorfor a Dask-chunked wind climate.add_met_fieldsadded a size-onepointdimension to a scalar wind climate.bwc_resample_wsbins_like(fit_weibull=False)passesAandkto the WAsP core.bwc_resample_sectorstruncated a fractionaloffset, sooffset=0.5did nothing.bwc_from_tswckeeps the input’s attributes, accepts spatial structures such asraster, and no longer raisesAttributeErrorwhen it warns about bin overflow.get_return_windread apointPEWC stored(point, year)in the wrong order, andget_spec_corr_fackilled the Python process for apointtime series stored(point, time).get_spec_corr_facapplied a spatially misalignednto the wrong points; it now raises.stability_histogram,create_histogram_z0andbaroclinicity_histogramfailed forstacked_pointandcuboidinputs, andstability_histogramandcreate_histogram_z0also forrasterand single-height inputs with the defaultfinalize=True.create_histogram_z0(finalize=True, landmask=...)returnedmean_z0with a spurious extra dimension forstacked_pointandcuboidinput.stability_histogramrejected a matchinghistand accepted a mismatched one.baroclinicity_histogram,stability_histogramandcreate_histogram_z0no longer modify a suppliedwv_count, so reusing an accumulator no longer double-counts a chunk.baroclinicity_histogramvalidates supplied count bins and keeps multi-height baroclinicity fields.Finalized histograms work with process-based Dask Distributed schedulers.
stability_histogramandbaroclinicity_histogramkeep the attributes of thecrscoordinate with olderxarrayandpyprojversions.Polygon land-cover maps lost internal roughness changes at the map edge: an edge shared by two polygons, with both ends on the map boundary, was clipped as the map edge, so
get_site_effectsandget_rou_rosemissed the roughness change behind it. A map of separate regions that does not fill its bounding box is now clipped, and a single-class map seesexternal_roughnessbeyond its edge.get_rou_rosewith a polygon map computed every point after the first from uninitialised memory, giving results that depended on the other points and occasional crashes. It raisesCoreErrorif polygon conversion fails.TopographyMap.get_rou_roseno longer modifies a suppliedelev_rose, and raises when its points don’t matchoutput_locs.Site effects from line maps could hold negative, uninitialised RIX values on repeated calls.
RIX at sites outside the elevation raster used swapped bilinear weights.
Raster elevation maps with non-square cells used the
west_eastresolution for both axes, which changes RIX and site effects. Descending axes are supported.Multi-height LINCOM wind-point results keep the terrain elevation two-dimensional, and placeholder site effects carry the right metadata, including a zero
flow_sep_height.vector_to_rasterno longer always warns aboutreturn_lctable/map_typefor line roughness maps.A polygon roughness map with the terrain analysis of WAsP before 12.7 raises an error that suggests
pw.polygons_to_lines().Invalid license credentials are no longer reported as a connection failure or retried; retries could get an IP address blocked by the license server.
The AEP functions,
get_air_densityand LINCOMcreate_fourier_spaceraise WAsP core errors as themselves instead of as license errors.Mesoclimate downloads fall back to the DTU Data mirror when Zenodo fails, which they never did, and raise
MesoclimateMissingErrorwhen both fail.pywasp configureon Windows no longer crashes when output is redirected or piped, writes the configuration file as UTF-8 so non-ASCII paths work, cancels cleanly on Ctrl+C or closed input, and exits non-zero when cancelled or failed.The
pywaspcommand works from the conda package on Windows, where it failed with “Fatal error in launcher”.create_config_interactivelyreturns the createdSettingsinstead ofNone.The AEP calculations work with xarray 2026.04.
Breaking changes#
PyWAsP requires Python 3.12 or later and windkit 2.2.
The default generalization heights are WAsP’s
[10, 25, 50, 100, 200]instead of[10, 25, 50, 100, 250], and Weibull fits use WAsP’s setting, which lowersAby about 0.02 %. Results above 100 m change slightly, for example by about 0.2 % in mean wind speed at 150 m.import pywaspno longer fetches the global mesoclimate files. The first calculation that needs them downloads them: withdownload_prompt = true(the default) after one y/n prompt in a terminal, and without asking where nothing can prompt. Withdownload_global_nc_files = false(orPYWASP_DOWNLOAD__DOWNLOAD_GLOBAL_NC_FILES=False), a declined prompt or a failed download,get_air_density,get_climateand the functions built on them raisepywasp.MesoclimateMissingErrorinstead ofEOFError,FileNotFoundErroror arequestsexception.Scalar spatial inputs give scalar outputs instead of gaining a size-one
pointdimension, and inputs with a scalarheightcoordinate, such as araster, keep it instead of gaining a size-oneheightdimension. This coversgross_aep,potential_aep(also withwind_turbines),TopographyMap.get_site_effects,get_site_effects_raster,convert_to_classes,wwc_rotate,align_direction_crs, thebwc_resample_*functions,apply_lut, and Wind Atlas downscaling and prediction. Explicitly dimensional single points stay dimensional, and scalar AEP results carry nogrid_mappingattribute.Dimension order is not guaranteed, so compare results by label.
gross_aepreturns point results as(sector, point)instead of(point, sector)and keeps a descending grid axis in the wind climate’s order, wherepotential_aepsorts it ascending.wwc_rotateandalign_direction_crskeep the input’s dimension order, and site effects returned withreturn_site_effects=Truekeep the order they were given in.gross_aepraisesPywaspErrorinstead ofValueErrorfor a Dask-chunked wind climate.The
generalize*functions keep the sourceheightdimension on their wind climate variables, including a single height, as the GeoWC functions do.calc_temp_scaleis height-independent; its spatial outputs have noheightdimension.Finalized
stability_histogramandbaroclinicity_histogramfields keep aheightdimension for multi-height inputs, and the Wind Atlas functions reject a mesoclimate with more than one independent height. Select a single height, or usepointdata withheight(point).The Wind Atlas functions take height-independent inputs once per horizontal location, so they raise
PywaspErrorfor a suppliedmesoclimatewhose values differ between points at the same location, or for site effects whosez0mesoorslfmesodiffer there.baroclinicity_histogram(hist=..., finalize=True)requireswv_count, the accumulated wind-vector counts of every chunk added tohist, and raisesPywaspErrorwithout it. PyWAsP 2.0 used the counts of the final chunk only, which inflatedmean_dgdz.TopographyMaprejects an elevation raster with NaN or Inf cells when it is constructed or loaded, raisingPywaspErrorinstead of a laterValueError.TopographyMap.elev_mapis read-only.TopographyMap.get_site_effects_cfdreturns NaN forcfd_speedups,cfd_turnings,cfd_turbulence_intensityandcfd_flow_inclinationat heights below or above the CFD volume, instead of values from its second or top level.convert_to_classesrequires arasterinput and raisesWindkitValidationErrorotherwise.bwc_resample_wsbins_like(fit_weibull=False)requiressourceandtargetto have the same spatial structure.interpolate_gwcno longer hasengine="fortran"; any value other than"windkit"raisesValueError.method="natural"onto araster,cuboidorstacked_pointtarget has no replacement.get_return_windraisesCoreErrornaming the cause when the Gumbel fit fails (fewer than two years, areturn_periodbelow one year, or apewc_max_intervalof 0 or less), instead of returning-999or 0 and anierrorvariable, which is removed.A yearly total from
gross_aep,potential_aeporwind_farm_flow_mapis missing when any of its sectors is, instead of summing the sectors that are present.potential_aep_deficitandwspd_deficitare the deficits of the all-sector values beside them (1 - potential_aep / gross_aepand1 - wspd_eff / wspd), instead of a frequency-weighted mean of the sector deficits that disagreed with the AEP. A location with no energy in any sector reports them as undefined instead of 0.potential_aepandwind_farm_flow_mapno longer return amodecoordinate.The
shearargument ofpotential_aepandwind_farm_flow_mapis removed; it had no effect. The positional arguments ofwind_farm_flow_mapafterturbulence_intensitymove up one place.The
generalize*andpredict*functions ignore ameridian_convergencevariable in the binned wind climate and compute it from the CRS instead. Results change where it was nonzero.Site effects that were reprojected by hand to another CRS than they were made in may give different results in
downscale_from_site_effects.pywasp.wasp.cross_predictreads the site coordinates from the wind climate files instead of the CSV, whoseepsgcolumn is optional, and renames its directories:tabfiles/towind_climates/,mapfiles/tomaps/,landcovertables/tolandcover_tables/andnetcdf/tocache/, which holds FlatGeobuf instead of parquet files.
Deprecations#
The
ws_lower_limitargument ofpotential_aepandwind_farm_flow_mapwill be removed in pywasp 3.0, and any value other than0.0warns. A float is ignored, since the wind speeds start at 0 m/s;Nonestill starts them at cut-in and has no replacement.Deprecation warnings name the version that deprecated the feature and, where decided, the version that removes it. pywasp 3.0 removes
generalize_and_downscale, thegetparandputparmethods ofConfig.climateandConfig.terrain,user_config.check_remaining_runs, and passing aWaspVectorMaptoTopographyMap.check_remaining_runsand themeridian_convergencewarning emitFutureWarninginstead ofDeprecationWarning, which Python hides unless it is triggered from__main__.
Changes#
License handling is lazy:
import pywaspworks offline and without a configuration, and the license is checked at the first licensed calculation, with actionable errors when the configuration is missing or invalid.The license tier’s point limit is enforced: a larger calculation raises
pywasp.PointsLimitError, so split it up. The limit is cached locally for 24 hours.potential_aepandwind_farm_flow_mapapply the WAsP parked-rotor convention: outside its operating range a turbine keeps its stationary thrust coefficient instead of exerting no thrust. Wake results change slightly around cut-in and cut-out.potential_aepandwind_farm_flow_mapsimulate about a third fewer wind speed cases. AEP is unchanged, and mean wind speeds move by less than 1e-6 relative.Binned wind climate histograms from Dask time series are faster: they skip eager chunk alignment, merge fine-grained time chunks, and reuse the land/sea nearest-neighbour mappings across stability fields.
baroclinicity_histogramraisesPywaspErrorfor unknown keyword arguments instead of ignoring them.The air density warnings from
potential_aepandwind_farm_flow_mappoint at the calling code, sowarningsfilters on the caller’s module work.The spatial coordinates of
cuboidandstacked_pointresults from Wind Atlas downscaling carry their CF attributes, andapply_lutkeeps its V50 wind attributes.The pip package declares its runtime dependencies, so pip and uv install numpy, xarray, windkit, py_wake and the rest. The conda package uses the same list and lower bounds, and
tabulateis no longer a dependency.The installation guide authenticates to the WAsP conda channel with
pixi auth loginandmamba auth login; a token embedded in the channel URL fails with mamba 2.The documentation has a version switcher, and a page on how AI coding assistants are used in PyWAsP’s development, which sits with the release notes under “Development”.
Documentation: the WAsP flow model page documents WAsP 12.10 as the default
Config, the user guide and “From WAsP to PyWAsP” have corrected examples, the LINCOM page outlines its workflow, the glossary defines the wind climate abbreviations, and the API reference lists more functions. The user guide and gallery load their data withwindkit.load_tutorial_data.
2.0.0 (2026-01-29)#
PyWAsP 2.0.0 contains many bugfixes that have been found since the 1.0 release, and includes better support for the geostrophic wind climate.
Bug fixes#
Increased maximum number of iterations to solve the geostrophic drag from the drag law from 10 to 50. This fixed some edge cases with high geostrophic wind shear, where the previous iterations limit was hit.
Ensure that frequencies are always positive in
bwc_resample_like. Fixes issue where numerical noise could cause them to go below zero. These are obviously unphysical, and resulted in negative moments in some edge cases when interpolating geostrophic wind climates over the whole european domain.Set correct dimensions of
hr1, hi1, hi2in fortran routine used byget_elev_roseto prevent code from hanging.Removed boolean attributes that were added in
bwc_from_tswcto allow the result to be written to NetCDF.Bug fix in internal functions of
potential_aepwhen passing wtg in a de-rated or storm mode.Made
floatintodoubleforpolygons_to_linesconversion: in some edge case the routines could create maps with errors, due to lack of precision.
New features#
Added new function roughness_to_landcover in pywasp which converts a roughness raster to a landcover map, with optional simplification.
stability_histogramnow supports all spatial structures instead of only cuboidsUpdated
pw.wasp.Configto use exact WAsP version numbers.Added
fill_valueargument tointerpolate_gwc, which controls the behaviour for points that are outside the convex hull given by the generalized wind climate. Formethod='nearest'results are also returned outside the convex hull. The function also works correctly for geostrophic wind climates now.You can now use the function
downscale_from_site_effectsto downscale both a generalized and geostrophic wind climate.New command-line interface:
pywasp configurefor interactive license setup andpywasp statusto check license status and remaining runs.New example: “Generalized wind climate interpolation”
New example: “Polygon and change line conversions”
Performance improvements#
Performance improvement in
potential_aepandwind_farm_flow_map: vectorized power curve operations using Numba with parallel processing, replacing iterative Fortran calls. Also switched from single to double precision for improved numerical accuracy.Function
pw.bwc_from_tswcis now twice as fast
Breaking changes#
downscale,downscale_from_site_effects,downscale_from_geostrophic_and_site_effects_to_bwc,predict_wwcandpredict_bwcall useinterp_method="nearest"by default. If you are using more than one observation as input this will change your results.interp_method="cubic"has been removed as option, because it can give unrealistic results for strongly varying gwc’s.downscale_from_geostrophic_and_site_effects_to_wwcis deprecated, and has been made private. You should now use the functiondownscale_from_site_effects(see above).Revamped pydantic based WAsP configuration, which is still experimental. Renamed it from
PywaspConfigtoParams(pywasp.wasp.params.Params); updated it to better follow pydantic syntax; removed initialization by WAsP version string, instead have to call thefrom_par_setclass method.
Documentation#
New updated PyData sphinx theme
Improved Installation documentation with tabs for conda/mamba vs pixi, collapsible troubleshooting sections, and clearer step-by-step instructions.
Moved several parts of pywasp docs to windkit docs (where they belong)
1.0.1 (2025-08-05)#
PyWAsP 1.0.1 is a bugfix release to fix an issue with the root_ca_filepath license option.
1.0.0 (2025-06-20)#
PyWAsP 1.0.0 is a major release that introduces a significant number of new features, improvements, and breaking changes aimed at improving the user experience, consistency, and performance. The API has been cleaned up, and many functions have been renamed for clarity. This version also introduces a new configuration system and enhanced energy yield calculation capabilities.
Dependency updates for 1.0#
Supports Python 3.11 to 3.13
Supports numpy 1.26 to 2.2 (1.0 will be last version to support numpy 1)
Supports PyWake 2.6
Supports windkit 1.0
Code restructuring and API cleanup#
Updated user config: The user configuration has migrated from
pywasp.cfgto a pydantic-based settings system. Users must create apywasp_config.tomlfile or a.envfile, or define environment variables. See the User Configuration documentation for details. A helper functionpywasp.user_config.create_config_interactively()can be used to create a new configuration file interactively.API Renaming and Cleanup:
The
pywasp.configmodule is renamed topywasp.user_config.pywasp.wasp.bwc_from_timeseriesis renamed topywasp.wasp.bwc_from_tswc.pywasp.io.rastermap_to_vectormapis renamed topywasp.io.raster_to_vector.pywasp.io.vectormap_to_rastermapis renamed topywasp.io.vector_to_raster.
Argument Renaming for Consistency:
The
return_site_factorsargument is renamed toreturn_site_effectsin alldownscale,predict, andgeneralizefunctions.Arguments for the number of wind speed bins (e.g.,
nwsbins,n_bins) are standardized ton_wsbins.Arguments for the number of sectors (e.g.,
nsec,nwd) are standardized ton_sectors.The
ws_bin_widthargument is renamed towsbin_width.In
pywasp.wasp.gross_aep,interpolateis renamed toair_density_correction, andair_densityis renamed toreference_air_density.In
pywasp.io.vector_to_raster, argumentsxmin,ymin,xmax,ymaxare replaced by a singleboundstuple.
Removed Functionality:
The following functions and classes have been removed from the public API:
pywasp.io.rastermap_to_waspformat,pywasp.io.vectormap_to_waspformat,pywasp.wasp.wtg_to_pywake,pywasp.lincom.grid_from_wasp_rastermap,pywasp.io.WaspVectorMap, andpywasp.io.WaspRasterMap.
Air density correction:
In
pywasp.wasp.gross_aep,pywasp.wasp.potential_aep, a newair_density_correctionargument was added, which defaults to"infer", which tries to infer the best air density correction method based on the WTG’s control system.pywasp.io.raster_to_vectornow returns polygons instead of change lines for roughness or landcover maps.Landcover tables are no longer required for
pywasp.io.raster_to_vectorandpywasp.io.vector_to_raster.
Metadata Changes:
The
_AEPsuffix in metadata attributes from AEP functions is now lowercase (_aep).The metadata variable
aep_deficitis renamed topotential_aep_deficit.
New features#
New energy yield calculation functions#
New function
pywasp.wasp.net_aepto calculate the Net Annual Energy Production (AEP) by applying losses from a loss table.New function
pywasp.wasp.estimate_sensitivity_factorto estimate the sensitivity factor of a wind effect to AEP.New function
pywasp.wasp.px_aepto calculate the AEP level reached with a given probability.
Landcover and I/O#
New function
pywasp.landcover.convert_to_classesthat adds new classes to a landcover raster map using tree heights and leaf area indices.New function
pywasp.io.polygons_to_linesthat converts polygons to lines, approximately 100x faster than thewindkitequivalent.pywasp.wasp.TopographyMapnow acceptsGeoDataFrames with Polygons.
Full list of changes#
New function
pywasp.landcover.convert_to_classesthat adds new classes to a landcover raster map using tree heights and leaf area indices raster maps.New keyword arugment
offsetinbwc_resample_sectorsthat allows rotating a histogram with a specified number of degreesBug fix in
interpolate_gwc: variables “m1”, “m3”, “fgtm” were not always removed. They are private variables that should never be visible to the user.get_air_density can now deal with larger than RAM memory dataset as input. The custom dataset can also be in any projection, whereas before it assumed it was always in latlon
Bug fix in
get_climate, did not work when bbox crosses dateline”New function
polygons_to_lines, that convert polygons to lines similar to the function windkit.poly_to_lines but approximately 100x times faster.In
interpolate_gwcfor interpolation of single point to many using keyword engine=”windkit”, could give wrong results when the output structure was not of the same spatial structure as the input spatial structure.PyWake is pinned to version 2.6.8 (commit 5562afda7f272ab029bf057617557c5de14416e5).
New functionality available,
potential_aepandwind_farm_flow_mapfunctions can now correct for site-specific air density conditions.In
gross_aep,potential_aepandwind_farm_flow_map, the argumentair_density_correctionis set to True by default.potential_aepcan now take different types of WTGs within the same wind farm group. Following the same structure asgross_aep.TopographyMap now allows input of Polygon dataframes, two extra keyword arguments
check_errorsandexternal_roughnessdetermine the behaviour when dealing with these maps. The external roughness length specifies the roughness outside the polygons in the provided map.
Breaking changes#
renamed
pw.wasp.bwc_from_timeseriestopw.wasp.bwc_from_tswcrenamed
pw.rastermap_to_vectormaptopw.raster_to_vectorrenamed
pw.vectormap_to_rastermaptopw.vector_to_raster.removed
pw.rastermap_to_waspformatfrom public namespaceremoved
pw.vectormap_to_waspformatfrom public namespaceremoved
pw.WaspVectorMapfrom public namespaceremoved
pw.WaspRasterMapfrom public namespaceremoved
pw.lincom.grid_from_wasp_rastermapfrom public namespaceArgument
return_site_factorshas been renamed toreturn_site_effectsin the following functions:downscaledownscale_from_site_effectsdownscale_from_geostrophic_and_site_effects_to_bwcdownscale_from_geostrophic_and_site_effects_to_wwcpredict_bwcpredict_bwc_from_site_effectspredict_wwcpredict_wwc_from_site_effectsgeneralize_from_site_effects_to_geowcgeneralize
Argument
nwsbins,nws,n_binshas been renamed ton_wsbinsin the following functions:bwc_from_tswcstability_histogramcreate_histogram_z0
Argument
nsec,nsecs,nwd,nbinshas been renamed ton_sectorsin the following functions:bwc_from_tswcstability_histogramcreate_histogram_z0get_elev_roseget_rou_roseget_site_effectsget_site_effects_cfdweibull_fitgeneralizepredict_wwcpredict_bwc
Argument
ws_bin_widthhas been renamed towsbin_widthin the following functions:bwc_from_tswcstability_histogramcreate_histogram_z0
Argument
interpolateingross_aephas been renamed toair_density_correction,air_densityhas been renamed toreference_air_density._AEPsuffix in attribute names of the metadata frompywasp.wasp.aep,pywasp.wasp.aep_losses.py,pywasp.wasp.aep_uncertainty.pyhave been changed to_aepMetadata variable name
aep_deficithas been renamed topotential_aep_deficitNo longer require landcover tables for
raster_to_vectorandvector_to_rasterReplaced arguments
xmin,ymin,xmax,ymaxinvector_to_rastertobounds(tuple or BBox of same values)raster_to_vectornow returns polygons instead of change lines when the input is a roughness or landcover map.Renamed
pywasp.configtopywasp.user_configto avoid confusion with thepywasp.wasp.Configclass.The “Roaming” AppData dir is now used on Windows. By default the config and app data files are stored in
"C:\\Users\\<user_name>\\AppData\\Roaming\\DTU Wind Energy\\pywasp"Removed function
pywasp.wasp.wtg_to_pywake(from public namespace)Replaced the gwc interpolation function in
pw.wasp.downscaleandpw.wasp.downscale_from_site_effectswith the newwk.spatial_interpolate_gwcfunction.This replaces the legacy gwc interpolaters in pywasp
With the update only “point” targets are supported for “natural” interpolation, while “nearest”, “linear”, and “cuboid” still works for all spatial structures.
Changed the
interp_methoddefault to “nearest” instead of “given”.
PyWAsP user configuration has migrated to using pydantic settings. This means that your pywasp.cfg will no longer work. You will need to either create a pywasp_config.toml file, a dotenv file, or define environment variables with your configuration settings for PyWAsP to import successfully. You can find the necessary information in the PyWAsP License and User Configuration documentation.
New energy yield calculation functions:#
New function
pywasp.wasp.net_aepto calculates the Net Annual Energy Production (AEP) by applying the losses from a loss table.New function
pywasp.wasp.estimate_sensitivity_factorto estimate the sensitivity factor of wind effect to AEP for a given predictive wind climate and wtg.New function
pywasp.wasp.px_aepto calculate the Annual Energy Production (AEP) level reached with a given probability.
0.7.0 (2024-06-04)#
PyWAsP 0.7.0 is a major release with new features, improvements, and bug fixes.
Dependency updates#
Following SPEC 0 this release supports python 3.10-3.12 and numpy 1.24-1.26.
Windkit =0.8.0 is required
PyWake is pinned to version 2.5.0 (commit 36da70b2335321e435194d277511c17d8f012571).
New features#
New climate extrapolation functions#
New function
pywasp.wasp.predict_wwcto predict a weibull wind climate from a binned wind climate without using a generalized wind climate lookup-table, thus reducing interpolation errorsNew function
pywasp.wasp.predict_bwc, same as above but to predict a binned wind climate instead.New function
pywasp.wasp.predict_wwc_from_site_effects, same aspywasp.wasp.predict_wwcbut using the outputs of calls topywasp.wasp.TopographyMap.get_site_effectsinstead of a mapfile.New function
pywasp.wasp.predict_bwc_from_site_effects, same aspywasp.wasp.predict_bwcbut using the outputs of calls topywasp.wasp.get_site_effectsinstead of a mapfile.New function
pywasp.wasp.generalize_from_site_effects, same aspywasp.wasp.generalizebut using the output of a call topywasp.wasp.TopographyMap.get_site_effectsinstead of a mapfile.New function
pywasp.wasp.generalize_from_site_effects_to_geowc, generalize a binned geostrophic wind climate from a site effects dataset.New function
pywasp.wasp.downscale_from_geostrophic_and_site_effects_to_bwc, downscale a binned geostrophic wind climate from a site effects dataset and geostrophic binned wind climate
BWC resampling functions added#
New function
pywasp.wasp.bwc_resample_like, to resample a binned wind climate using a different sector or wind speed bin structure.New function
pywasp.wasp.bwc_resample_sectors, to resample a binned wind climate using a different number of sectors.New function
pywasp.wasp.bwc_resample_wsbins_like, to resample a binned wind climate using a different wind speed bin structure.
I/O added to TopographyMap and new CFD data-extraction method#
New methods
.saveand.loadadded topywasp.wasp.TopographyMapto save and load the topography map to/from a ZipFile Archieve.pywasp.wasp.get_site_effects_cfdalso accepts a list of xr.datasets (read by theread_cfdresfunction in windkit) as input. It will extract the site effects in the order specified in the list.
Support for custom root CA certificates#
In case of running
pywaspunder a proxy or another similar network setup, the filepath to a root CA certificate can be set onpywaspso it can connect to the licensing server.
Improvements#
For typical usage
pywasp.wasp.TopographyMap.get_site_effectsis 2-6 times fasterFor typical usage
pywasp.io.rastermap_to_vectormapis 15-30 times fasterFor typical usage
pywasp.io.vectormap_to_rastermapis 15-30 times fasterFor typical usage
pywasp.io.vectormap_to_waspformatis 2-20 times fasterFor typical usage
pywasp.io.waspformat_to_vectormapis 2-80 times fasterFor typical usage
pywasp.wasp.TopographyMapis >1000 times fasterImproved input error checking in
pywasp.wasp.generalize()Improved input error checking in
pywasp.wasp.generalize(), check that thegen_roughnessesandgen_heightshave at least 2 entries, as required by the WAsP core.Improved input error checking in
pywasp.wasp.TopographyMap: make sure that all your landcover lines have a corresponding entry in the landcover table.More accurate setting of generalized heights and roughness using the function
pywasp.wasp.set_hgtsandpywasp.wasp.set_z0s. Now a percentile mapping technique is used when the number of heights or roughnesses exceeds the maximum number of entries allowed in agwc(5).More descriptive error codes when having problems reading a pywasp config file.
TopographyMap now throws an error when the lctable has more than 100 entries. Before this condition was unhandled and could crash the fortran.
pywasp.wasp.Configobject now is read only and does not do any modifications of the fortran behaviour itself (before it was creating lookup tables and setting some parameters on each update of conf.terrain.)
Deprecations#
WaspVectorMap will be deprecated
windkit.WindTurbinesdeprecated for AEP functions. Use a dict of WTGxr.Dataset’s and a wind_turbinexr.Datasetinstead.
Changes#
pywasp.wasp.generalizenow usespywasp.wasp.generalize_from_site_effectsinstead of duplicating codepywasp.wasp.interpolate_gwc-> Can now also interpolate geostrophic wind climates. Code from windkit has been implemented in pywasp and can be used by using the argumentengine="windkit".pywasp.wasp.TopographyMap.get_site_effectsnow reports an extra variableflow_sep_height, which can report the height where flow separation is expected based on slopes exceeding some given slope. Theflow_sep_heightis only active when usingconf.terrain[64] == 1.In all the downscale and generalize function an additional variable
flow_sep_heightcan be used. This is added to the displacement height that is used for transformation of the wind climate. If this data array is not present on thesite_effectsdataset, it is added automatically.Using a point dataset with multiple heights now gives a warning instead of a ValueError, because it is typically used in combination with
pywasp.wasp.interpolate_gwcand interp_method=”given” where it is fine to have more than one height.
Breaking changes#
pywasp.wasp.get_wasp_downrenamed topywasp.wasp.downscale_from_site_effectsChanged order of arguments in
pywasp.wasp.generalize_and_downscaleto bwc, topo_map, output_locs for consistency with generalize and downscalepywasp.wasp.set_hgts-> returns slightly more accurate generalized roughnesses whenheight_fromandheight_toare providedpywasp.wasp.set_z0s-> returns slightly more accurate generalized roughnesses whenz0meso_fromandz0meso_toare providedpywasp.wasp.calc_temp_scalethe output of the dataset now returns the correct nameustar_over_pblhpywasp.wasp.stability_histogramnow produces a dataset with the more correct namesmean_pblh_scale_landandmean_pblh_scale_seainstead ofmean_pblh_landandmean_pblh_sea. See for more details: https://link.springer.com/article/10.1007/s10546-023-00803-3genwc_interpargument indownscaleandgeneralizehas been renamed tointerp_methodpywasp.wasp.gross_aep,pywasp.wasp.potential_aep, andpywasp.wasp.wind_farm_flow_mapnow uses a dict{"wtg_key1": wtg1, "wtg_key2": wtg2}and a turbinesxarray.Datasetinstead of awindkit.WindTurbinesobject. WTGs are mapped to turbines via the wtg_keys present in both the dict and the turbines dataset.
0.6.0 (2023-11-30)#
Dependency updates#
Following SPEC 0 this release supports python 3.10-3.12 and numpy 1.22-1.26. Due to build issues with numpy 1.26, neither it nor python 3.12 are supported on Windows.
Windkit =0.7.0 is required
PyWake is now pinned to version 2.5.0 (commit 36da70b2335321e435194d277511c17d8f012571).
New features#
Support for WAsP CFD results#
New function
pywasp.wasp.get_site_effects_cfdinterpolates the speedups and turnings from awindkitCFD volumexarray.Dataset.pywasp.wasp.generalize,pywasp.wasp.downscale, andpywasp.wasp.generalize_and_downscalenow have an extracfd_volumeargument, which can be used to pass in WAsP CFD results that will be used for the site effects.
Breaking changes#
pywasp.wasp.wind_farm_flow_mapnow requires awk.WindTurbinesobject, not separate wtg and locations arguments.pywasp.wasp.wind_farm_flow_maprequires the new argumentoutput_locs, which should be a “cuboid”xr.Dataset, which is where the flow map will be calculated.output_locsshould be covered by the predicted wind climate object.
Changes#
Interpolation errors have been eliminated during the downscale step when using
pywasp.wasp.generalize_and_downscale, by including the output heights in the generalize step.Update ERA5 mesoclimate netCDF file according to latest revision of Using Observed and Modelled Heat Fluxes for Improved Extrapolation of Wind Distributions.
pywasp.wasp.gross_aepandpywasp.wasp.potential_aepcan now accept awk.WindTurbinesobject to thewtgargument. This allows for different WTGs to be used for different turbine locations.Added
interp_methodargument topywasp.wasp.get_climate, “nearest” is used by default
Improvements#
Reduction of approximately 50% for calculations of wake-affected AEP.
Bug Fixes#
PyWAsP on windows now can use the license.windenergy.dtu.dk licensing server.
Interpolation of
mean_dgdzandmean_dgdz_dirare now carried out by interpolating the vector components, when a method other than"nearest"is used.
Deprecations#
Deprecated options “PARK2_onshore_with_blockage” and “PARK2_offshore_with_blockage” in
pywasp.wasp.wind_farm_flow_mapandpywasp.wasp.potential_aep. Use, custom PyWake wind_farm_models to build complex models instead.
0.5.2 (2023-06-21)#
Changes#
Dependency updates: Python 3.8 & numpy 1.21 no longer supported following NEP 29. Windkit 0.6.3 is now required to support the
regulation_typevariable forwtgobjects.pywasp.wasp.TopographyMap.get_rou_rosenow allows to add displacements to the orographic grid, using the newelev_roseargument. Ifelev_roseis None, a dummy elevation rose is created.pywasp.wasp.interpolate_gwcnow returns an interpolated generalized wind climate dataset with height coordinates.
Setting
download_prompt=Falseanddownload_global_nc_filesin the pywasp.cfg file, will not prevent any text from showing when importing PyWAsP. Previously it would print a message about how to get the files on each import. If you need the files, you will be prompted to download at that time. See the User Configuration Documentation to see all options of the config file.
Improvements#
Update netCDF file with CFSR baroclinicity information. The data is the same but the data variable names are updated. It does not affect the behavior.
pywasp.wasp.interpolate_gwcwill issue a warning if it is used with datasets with geographical coordinates for “nearest” and “natural” methods.
Bug Fixes#
pywasp.io.rastermap_to_vectormapwill only raises errors related with the parameterdzwhen the raster map type iselevation.pywasp.wasp.aep.gross_aepincorrectly assumed most wind turbines were stall regulated. This means that when using theinterpolation=Trueoption, that incorrect air density corrections were applied. This has been fixed by an update in WindKit that requires thecontrol_systemvariable to be defined on a wind turbine generator. This value is now used to apply the correct air density correction to the power curves.
0.5.1 (2023-04-19)#
New Features#
pywasp.wasp.get_climate_by_configtakes apywasp.wasp.Configobject and returns anxarray.Datasetmeso climate object compatible with the profile model set in the config.
Changes#
pywasp.wasp.get_climateargumentsstab_sourceandbaro_sourcenow both allow forNoneto be set. This creates a dataset with 0-valued fields for the given source.
Improvements#
Update netCDF file with CFSR baroclinicity information to version 3. The data is the same, but the data variable names are updated. This does not affect the behavior.
Bug Fixes#
Fixed license check error for new version of DTU License server
Corrected import of
combine_bwcsinpywasp.wasp.cross_predict.pywasp.wasp.interpolate_gwcnow returns an interpolated generalized wind climate dataset with height coordinates. This makes it more robust to different spatial structures of generalized wind climates and output_locs, when used for downscaling.
Deprecations#
getparandputparmethods ofpywasp.wasp.config.Configobjects are deprecated. Use square brackets instead.