From 725f272c25df46b52cc8452b38336e890aba3546 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Thu, 13 Aug 2026 10:54:51 +0100 Subject: [PATCH 01/31] doc: changed version number --- wrf_analysis_toolkit/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrf_analysis_toolkit/pyproject.toml b/wrf_analysis_toolkit/pyproject.toml index b9ce7c0..58b113b 100644 --- a/wrf_analysis_toolkit/pyproject.toml +++ b/wrf_analysis_toolkit/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "wrf_analysis_toolkit" -version = "2.4.0" +version = "2.5.0" requires-python = ">=3.10" dependencies = [ "netCDF4>=1.7", From 6ffc25d006342c781bafb8706910f4981bf10865 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Thu, 13 Aug 2026 11:28:53 +0100 Subject: [PATCH 02/31] feat: initial sensible variable for mass tendency --- .../wrf_analysis_toolkit/SensibleVariables.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py index 8cf0a44..2549656 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py @@ -1476,3 +1476,45 @@ def create_PotentialVorticity_at( range_min=-60, range_max=40, ) + +# Sensible variables for analysing momentum tendency terms + +# mu_range_min = -10 +# mu_range_max = 10 +# mu_max_frac = 0.55 + min(0.45, (pv_range_max / (pv_range_max - pv_range_min))) +# mu_min_frac = 0.55 + min(0, (pv_range_min / (pv_range_max - pv_range_min))) +# mu_nticks = 11 +# mu_nlevs = 11 +MassTendency = svariable( + dim=4, + wrfname="MU_TEND2", + ptitle=f"Mass tendency [Pa/s]", + outfile=f"MassTendency", + colormap=get_cmap("YlGnBu"), +) +def create_MassTendency_at( + interpvalue, + # range_min=mu_range_min, + # range_max=mu_range_max, + # nticks=mu_nticks, + # nlevs=mu_nlevs +): + return svariable( + dim=4, + wrfname="MU_TEND2", + ptitle=f"Mass tendency at {interpvalue} hPa [PVU]", + outfile=f"MassTendency{interpvalue}", + interpvar="pressure", + interpvalue=interpvalue, + # colormap=cmr.get_sub_cmap("PuOr", min_frac, max_frac, N=nlevs), + # nticks=nticks, + # nlevs=nlevs, + # range_min=range_min, + # range_max=range_max, + ) + +MassTendency925 = create_MassTendency_at(925) #, range_min=-5, range_max=5) +MassTendency850 = create_MassTendency_at(850) #, range_min=-5, range_max=5) +MassTendency700 = create_MassTendency_at(700) #, range_min=-5, range_max=5) +MassTendency500 = create_MassTendency_at(500) #, range_min=-5, range_max=5) +MassTendency300 = create_MassTendency_at(300) #, range_min=-10, range_max=10) From a816bc9a4f7e71dde543976fbcf7e561826a172b Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Thu, 13 Aug 2026 11:34:03 +0100 Subject: [PATCH 03/31] fix: corrected mass tendency to be a 2D variable --- .../wrf_analysis_toolkit/SensibleVariables.py | 58 ++++++++++--------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py index 2549656..b2293f9 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py @@ -1477,44 +1477,48 @@ def create_PotentialVorticity_at( range_max=40, ) + # Sensible variables for analysing momentum tendency terms +# Mass Tendency 2D # mu_range_min = -10 # mu_range_max = 10 # mu_max_frac = 0.55 + min(0.45, (pv_range_max / (pv_range_max - pv_range_min))) # mu_min_frac = 0.55 + min(0, (pv_range_min / (pv_range_max - pv_range_min))) # mu_nticks = 11 # mu_nlevs = 11 -MassTendency = svariable( - dim=4, +MassTendency2 = svariable( + dim=3, wrfname="MU_TEND2", ptitle=f"Mass tendency [Pa/s]", outfile=f"MassTendency", colormap=get_cmap("YlGnBu"), ) -def create_MassTendency_at( - interpvalue, - # range_min=mu_range_min, - # range_max=mu_range_max, - # nticks=mu_nticks, - # nlevs=mu_nlevs -): - return svariable( - dim=4, - wrfname="MU_TEND2", - ptitle=f"Mass tendency at {interpvalue} hPa [PVU]", - outfile=f"MassTendency{interpvalue}", - interpvar="pressure", - interpvalue=interpvalue, - # colormap=cmr.get_sub_cmap("PuOr", min_frac, max_frac, N=nlevs), - # nticks=nticks, - # nlevs=nlevs, - # range_min=range_min, - # range_max=range_max, - ) -MassTendency925 = create_MassTendency_at(925) #, range_min=-5, range_max=5) -MassTendency850 = create_MassTendency_at(850) #, range_min=-5, range_max=5) -MassTendency700 = create_MassTendency_at(700) #, range_min=-5, range_max=5) -MassTendency500 = create_MassTendency_at(500) #, range_min=-5, range_max=5) -MassTendency300 = create_MassTendency_at(300) #, range_min=-10, range_max=10) + +# def create_MassTendency_at( +# interpvalue, +# # range_min=mu_range_min, +# # range_max=mu_range_max, +# # nticks=mu_nticks, +# # nlevs=mu_nlevs +# ): +# return svariable( +# dim=4, +# wrfname="MU_TEND2", +# ptitle=f"Mass tendency at {interpvalue} hPa [PVU]", +# outfile=f"MassTendency{interpvalue}", +# interpvar="pressure", +# interpvalue=interpvalue, +# # colormap=cmr.get_sub_cmap("PuOr", min_frac, max_frac, N=nlevs), +# # nticks=nticks, +# # nlevs=nlevs, +# # range_min=range_min, +# # range_max=range_max, +# ) + +# MassTendency925 = create_MassTendency_at(925) #, range_min=-5, range_max=5) +# MassTendency850 = create_MassTendency_at(850) #, range_min=-5, range_max=5) +# MassTendency700 = create_MassTendency_at(700) #, range_min=-5, range_max=5) +# MassTendency500 = create_MassTendency_at(500) #, range_min=-5, range_max=5) +# MassTendency300 = create_MassTendency_at(300) #, range_min=-10, range_max=10) From 5990beae187202fe6ca4cae0501830eba9a7e164 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Thu, 13 Aug 2026 11:52:23 +0100 Subject: [PATCH 04/31] feat: added UHorizAdvMomentum --- .../wrf_analysis_toolkit/SensibleVariables.py | 61 +++++++++---------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py index b2293f9..951d0f1 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py @@ -1487,38 +1487,37 @@ def create_PotentialVorticity_at( # mu_min_frac = 0.55 + min(0, (pv_range_min / (pv_range_max - pv_range_min))) # mu_nticks = 11 # mu_nlevs = 11 -MassTendency2 = svariable( - dim=3, - wrfname="MU_TEND2", - ptitle=f"Mass tendency [Pa/s]", - outfile=f"MassTendency", +UHorizAdvMomentum = svariable( + dim=4, + wrfname="RU_TEND_HADV", + ptitle=f"Horizontal advection of zonal coupled momentum term in X [Pa m s-2]", + outfile=f"UHorizAdvMomentum", colormap=get_cmap("YlGnBu"), ) +def create_UHorizAdvMomentum_at( + interpvalue, + # range_min=mu_range_min, + # range_max=mu_range_max, + # nticks=mu_nticks, + # nlevs=mu_nlevs +): + return svariable( + dim=4, + wrfname="RU_TEND_HADV", + ptitle=f"Horizontal advection of zonal coupled momentum term in X at {interpvalue} hPa [Pa m s-2]", + outfile=f"UHorizAdvMomentum{interpvalue}", + interpvar="pressure", + interpvalue=interpvalue, + # colormap=cmr.get_sub_cmap("PuOr", min_frac, max_frac, N=nlevs), + # nticks=nticks, + # nlevs=nlevs, + # range_min=range_min, + # range_max=range_max, + ) -# def create_MassTendency_at( -# interpvalue, -# # range_min=mu_range_min, -# # range_max=mu_range_max, -# # nticks=mu_nticks, -# # nlevs=mu_nlevs -# ): -# return svariable( -# dim=4, -# wrfname="MU_TEND2", -# ptitle=f"Mass tendency at {interpvalue} hPa [PVU]", -# outfile=f"MassTendency{interpvalue}", -# interpvar="pressure", -# interpvalue=interpvalue, -# # colormap=cmr.get_sub_cmap("PuOr", min_frac, max_frac, N=nlevs), -# # nticks=nticks, -# # nlevs=nlevs, -# # range_min=range_min, -# # range_max=range_max, -# ) - -# MassTendency925 = create_MassTendency_at(925) #, range_min=-5, range_max=5) -# MassTendency850 = create_MassTendency_at(850) #, range_min=-5, range_max=5) -# MassTendency700 = create_MassTendency_at(700) #, range_min=-5, range_max=5) -# MassTendency500 = create_MassTendency_at(500) #, range_min=-5, range_max=5) -# MassTendency300 = create_MassTendency_at(300) #, range_min=-10, range_max=10) +UMassTendency925 = create_UHorizAdvMomentum_at(925) #, range_min=-5, range_max=5) +UMassTendency850 = create_UHorizAdvMomentum_at(850) #, range_min=-5, range_max=5) +UMassTendency700 = create_UHorizAdvMomentum_at(700) #, range_min=-5, range_max=5) +UMassTendency500 = create_UHorizAdvMomentum_at(500) #, range_min=-5, range_max=5) +UMassTendency300 = create_UHorizAdvMomentum_at(300) #, range_min=-10, range_max=10) From 33eaf8c23463e124ebffc334c1e32c7633bfb255 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Thu, 13 Aug 2026 12:13:03 +0100 Subject: [PATCH 05/31] fix: added function to destagger dimensions --- .../wrf_analysis_toolkit/GetSensVar.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index cc0e0b7..891d6d0 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -1,4 +1,4 @@ -from wrf import to_np, getvar, g_geoht, interplevel +from wrf import to_np, getvar, g_geoht, interplevel, destagger import numpy as np import wrf_analysis_toolkit.SensibleVariables as sv @@ -41,6 +41,21 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): F3D = Frontogenesis.frontogenesis3D(ncfile, time) d4var = getvar(ncfile, svariable.interpvar, timeidx=time) d4var.values = F3D + + # Destagger the variable if it is staggered + stagger_dim = None + for i, dim in enumerate(d4var.dims): + if dim.endswith("_stag"): + stagger_dim = i + print(f"Destaggering {svariable.outfile} along {i}") + break + if stagger_dim: + try: + d4var = destagger(d4var, stagger_dim) + except: + raise ValueError(f"Unable to destagger {svariable.outfile}") + + # interpolate variable var = interplevel(d4var, interpvar, svariable.interpvalue) # Special variable computation if "AirTempDif6h" in svariable.outfile: From 880befe9417804ab6077dd7bf58942af3592b02f Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Thu, 13 Aug 2026 12:15:10 +0100 Subject: [PATCH 06/31] fix: changed destaggering to preserve metadata --- wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index 891d6d0..1a58f04 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -47,11 +47,11 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): for i, dim in enumerate(d4var.dims): if dim.endswith("_stag"): stagger_dim = i - print(f"Destaggering {svariable.outfile} along {i}") + print(f"Destaggering {svariable.outfile} along dim {i}") break if stagger_dim: try: - d4var = destagger(d4var, stagger_dim) + d4var = destagger(d4var, stagger_dim, meta=True) except: raise ValueError(f"Unable to destagger {svariable.outfile}") From 9404c889d863455b60b2e9b3ad542286a9fd3ee4 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Thu, 13 Aug 2026 13:38:58 +0100 Subject: [PATCH 07/31] exp: testing if time value exists in original variable --- wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py | 1 + 1 file changed, 1 insertion(+) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index 1a58f04..ec22e93 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -43,6 +43,7 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): d4var.values = F3D # Destagger the variable if it is staggered + print(str(d4var.Time.values)[0:19]) stagger_dim = None for i, dim in enumerate(d4var.dims): if dim.endswith("_stag"): From 1041e133de5ecb4c159fe556d002ea9ca6127571 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Thu, 13 Aug 2026 13:39:40 +0100 Subject: [PATCH 08/31] exp: testing d4var dims --- wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py | 1 + 1 file changed, 1 insertion(+) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index ec22e93..faa66fe 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -43,6 +43,7 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): d4var.values = F3D # Destagger the variable if it is staggered + print(str(d4var.dims)) print(str(d4var.Time.values)[0:19]) stagger_dim = None for i, dim in enumerate(d4var.dims): From a83b9bd01be47435890d7704f82da8f894eab9d1 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Thu, 13 Aug 2026 14:03:08 +0100 Subject: [PATCH 09/31] fix: readding time var after variable is destagered --- wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index faa66fe..281c732 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -53,9 +53,12 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): break if stagger_dim: try: + vartime = d4var.Time d4var = destagger(d4var, stagger_dim, meta=True) + d4var.Time = vartime # Need to redfine time as lost in destagger step except: raise ValueError(f"Unable to destagger {svariable.outfile}") + print(str(d4var.Time.values)[0:19]) # interpolate variable var = interplevel(d4var, interpvar, svariable.interpvalue) From d959757f8f0086ad6a43c18f08e7c4ac16799bcc Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Thu, 13 Aug 2026 14:18:17 +0100 Subject: [PATCH 10/31] exp: testing reassignment of Time using ['Time'] --- wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index 281c732..e04063d 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -55,7 +55,7 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): try: vartime = d4var.Time d4var = destagger(d4var, stagger_dim, meta=True) - d4var.Time = vartime # Need to redfine time as lost in destagger step + d4var['Time'] = vartime # Need to redfine time as lost in destagger step except: raise ValueError(f"Unable to destagger {svariable.outfile}") print(str(d4var.Time.values)[0:19]) From 4b8ef03a991ba5a682121386a6296bb993d7b951 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Thu, 13 Aug 2026 14:25:00 +0100 Subject: [PATCH 11/31] debug: testing whether setting coords to P field works --- wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index e04063d..97b312c 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -45,6 +45,7 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): # Destagger the variable if it is staggered print(str(d4var.dims)) print(str(d4var.Time.values)[0:19]) + print(str(d4var.coords)) stagger_dim = None for i, dim in enumerate(d4var.dims): if dim.endswith("_stag"): @@ -53,12 +54,14 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): break if stagger_dim: try: - vartime = d4var.Time d4var = destagger(d4var, stagger_dim, meta=True) - d4var['Time'] = vartime # Need to redfine time as lost in destagger step + # Coordinates are lost during restaggering, so set based in interp field + d4var.assign_coords = interpvar.coords except: raise ValueError(f"Unable to destagger {svariable.outfile}") + print(str(d4var.dims)) print(str(d4var.Time.values)[0:19]) + print(str(d4var.coords)) # interpolate variable var = interplevel(d4var, interpvar, svariable.interpvalue) From 5f732546f9afc9924b02f9082e20e5c2f9d2678f Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Thu, 13 Aug 2026 14:28:01 +0100 Subject: [PATCH 12/31] fix: corrected syntax for assign_coords --- wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index 97b312c..3b54dd2 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -56,7 +56,7 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): try: d4var = destagger(d4var, stagger_dim, meta=True) # Coordinates are lost during restaggering, so set based in interp field - d4var.assign_coords = interpvar.coords + d4var.assign_coords(interpvar.coords) except: raise ValueError(f"Unable to destagger {svariable.outfile}") print(str(d4var.dims)) From 9e616ee1640e92c397e825f2a411b1c0362e0137 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Thu, 13 Aug 2026 14:31:01 +0100 Subject: [PATCH 13/31] fix: assigning time explictly too --- wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py | 1 + 1 file changed, 1 insertion(+) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index 3b54dd2..783c78a 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -57,6 +57,7 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): d4var = destagger(d4var, stagger_dim, meta=True) # Coordinates are lost during restaggering, so set based in interp field d4var.assign_coords(interpvar.coords) + d4var["Time"] = interpvar.Time except: raise ValueError(f"Unable to destagger {svariable.outfile}") print(str(d4var.dims)) From cb26383d854db76384b34fb02c65780445044b5e Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Fri, 14 Aug 2026 10:33:14 +0100 Subject: [PATCH 14/31] exp: trying to understand coordinates used by other variables --- wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py | 1 + 1 file changed, 1 insertion(+) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index 783c78a..c6cdc7d 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -32,6 +32,7 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): # For 3D +value variables, interpolated at interpvalue of interpvar elif svariable.dim == 4: interpvar = getvar(ncfile, svariable.interpvar, timeidx=time) + print(str(interpvar.coords)) if svariable.wrfname is not None: d4var = getvar(ncfile, svariable.wrfname, timeidx=time) # Special variable acquisition From 4d3f4691c2c7ef9e364c42b3897171fb92ea8852 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Fri, 14 Aug 2026 10:42:23 +0100 Subject: [PATCH 15/31] exp: trying to set coords via a dict --- .../wrf_analysis_toolkit/GetSensVar.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index c6cdc7d..d1a5baa 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -32,7 +32,8 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): # For 3D +value variables, interpolated at interpvalue of interpvar elif svariable.dim == 4: interpvar = getvar(ncfile, svariable.interpvar, timeidx=time) - print(str(interpvar.coords)) + print("Pressure coords:") + print(dict(interpvar.coords)) if svariable.wrfname is not None: d4var = getvar(ncfile, svariable.wrfname, timeidx=time) # Special variable acquisition @@ -44,8 +45,7 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): d4var.values = F3D # Destagger the variable if it is staggered - print(str(d4var.dims)) - print(str(d4var.Time.values)[0:19]) + print("d4var cords coords before:") print(str(d4var.coords)) stagger_dim = None for i, dim in enumerate(d4var.dims): @@ -57,12 +57,12 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): try: d4var = destagger(d4var, stagger_dim, meta=True) # Coordinates are lost during restaggering, so set based in interp field - d4var.assign_coords(interpvar.coords) + d4var + d4var.assign_coords(coords=dict(interpvar.coords)) d4var["Time"] = interpvar.Time except: raise ValueError(f"Unable to destagger {svariable.outfile}") - print(str(d4var.dims)) - print(str(d4var.Time.values)[0:19]) + print("d4var cords coords after:") print(str(d4var.coords)) # interpolate variable From bef3986c3a0da5d2b30751514d97b8dcc2305162 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Fri, 14 Aug 2026 10:55:46 +0100 Subject: [PATCH 16/31] fix: manually assigning coordinates to dimensions --- .../wrf_analysis_toolkit/GetSensVar.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index d1a5baa..55eb6be 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -32,8 +32,6 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): # For 3D +value variables, interpolated at interpvalue of interpvar elif svariable.dim == 4: interpvar = getvar(ncfile, svariable.interpvar, timeidx=time) - print("Pressure coords:") - print(dict(interpvar.coords)) if svariable.wrfname is not None: d4var = getvar(ncfile, svariable.wrfname, timeidx=time) # Special variable acquisition @@ -56,9 +54,12 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): if stagger_dim: try: d4var = destagger(d4var, stagger_dim, meta=True) - # Coordinates are lost during restaggering, so set based in interp field - d4var - d4var.assign_coords(coords=dict(interpvar.coords)) + # Manually assign coordinates from interpvar because these aren't done automatically + d4var.assign_coords(coords=interpvar.coords) + d4var.assign_coords({ + 'XLONG', (('south_north', 'west_east'), interpvar.coords['XLONG'].values), + 'XLAT', (('south_north', 'west_east'), interpvar.coords['XLAT'].values) + }) d4var["Time"] = interpvar.Time except: raise ValueError(f"Unable to destagger {svariable.outfile}") From aebf7f0e18d66d464b016cc51d9c06062082b19c Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Fri, 14 Aug 2026 10:57:53 +0100 Subject: [PATCH 17/31] fix: corrected dict syntax --- wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index 55eb6be..2c666e1 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -57,8 +57,8 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): # Manually assign coordinates from interpvar because these aren't done automatically d4var.assign_coords(coords=interpvar.coords) d4var.assign_coords({ - 'XLONG', (('south_north', 'west_east'), interpvar.coords['XLONG'].values), - 'XLAT', (('south_north', 'west_east'), interpvar.coords['XLAT'].values) + 'XLONG': (('south_north', 'west_east'), interpvar.coords['XLONG'].values), + 'XLAT': (('south_north', 'west_east'), interpvar.coords['XLAT'].values) }) d4var["Time"] = interpvar.Time except: From 1251915d12e5621084c23bc3e89d689e8aa89dd5 Mon Sep 17 00:00:00 2001 From: scottan <33283688+Scottan@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:04:54 +0000 Subject: [PATCH 18/31] fix: got staggering of variables to work with correct metadata --- .../wrf_analysis_toolkit/GetSensVar.py | 11 +-- .../wrf_analysis_toolkit/SensibleVariables.py | 78 +++++++++++++++---- 2 files changed, 64 insertions(+), 25 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index 2c666e1..9677cda 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -43,8 +43,6 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): d4var.values = F3D # Destagger the variable if it is staggered - print("d4var cords coords before:") - print(str(d4var.coords)) stagger_dim = None for i, dim in enumerate(d4var.dims): if dim.endswith("_stag"): @@ -55,16 +53,11 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): try: d4var = destagger(d4var, stagger_dim, meta=True) # Manually assign coordinates from interpvar because these aren't done automatically - d4var.assign_coords(coords=interpvar.coords) - d4var.assign_coords({ - 'XLONG': (('south_north', 'west_east'), interpvar.coords['XLONG'].values), - 'XLAT': (('south_north', 'west_east'), interpvar.coords['XLAT'].values) - }) + d4var = d4var.assign_coords(coords=interpvar.coords) + d4var.attrs.update(stagger=interpvar.attrs['stagger'], coordinates=interpvar.attrs['coordinates']) d4var["Time"] = interpvar.Time except: raise ValueError(f"Unable to destagger {svariable.outfile}") - print("d4var cords coords after:") - print(str(d4var.coords)) # interpolate variable var = interplevel(d4var, interpvar, svariable.interpvalue) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py index 951d0f1..9e60a71 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py @@ -977,7 +977,6 @@ def create_GeoPotHeight_at( range_max=128, ) -# Frontgenesis Frontogenesis925 = svariable( dim=4, ptitle="Petterssen Frontogenesis at 925 hPa [K/(100km 3h)]", @@ -1226,6 +1225,29 @@ def create_WindSpeed_at(interpvalue, range_min=0, range_max=60, nticks=12, nlevs WindSpeed500 = create_WindSpeed_at(500) WindSpeed300 = create_WindSpeed_at(300, range_min=0, range_max=80) +def create_U_at(interpvalue, range_min=0, range_max=60, nticks=12, nlevs=12): + return svariable( + dim=4, + wrfname="U", + ptitle=f"Wind Speed in West-East direction at {interpvalue} hPa [m/s]", + outfile=f"U{interpvalue}", + interpvar="pressure", + interpvalue=interpvalue, + colormap=get_cmap("YlGnBu"), + nticks=nticks, + nlevs=nlevs, + range_min=range_min, + range_max=range_max, + windbarbs=True, + ) + +U925 = create_U_at(925) +U850 = create_U_at(850) +U700 = create_U_at(700) +U500 = create_U_at(500) +U300 = create_U_at(300, range_min=0, range_max=80) + + # Potential Vorticity pv_range_min = -10 pv_range_max = 10 @@ -1481,12 +1503,12 @@ def create_PotentialVorticity_at( # Sensible variables for analysing momentum tendency terms # Mass Tendency 2D -# mu_range_min = -10 -# mu_range_max = 10 -# mu_max_frac = 0.55 + min(0.45, (pv_range_max / (pv_range_max - pv_range_min))) -# mu_min_frac = 0.55 + min(0, (pv_range_min / (pv_range_max - pv_range_min))) -# mu_nticks = 11 -# mu_nlevs = 11 +mu_range_min = -100 +mu_range_max = 100 +mu_max_frac = 0.55 + min(0.45, (pv_range_max / (pv_range_max - pv_range_min))) +mu_min_frac = 0.55 + min(0, (pv_range_min / (pv_range_max - pv_range_min))) +mu_nticks = 21 +mu_nlevs = 21 UHorizAdvMomentum = svariable( dim=4, wrfname="RU_TEND_HADV", @@ -1497,11 +1519,13 @@ def create_PotentialVorticity_at( def create_UHorizAdvMomentum_at( interpvalue, - # range_min=mu_range_min, - # range_max=mu_range_max, - # nticks=mu_nticks, - # nlevs=mu_nlevs + range_min=mu_range_min, + range_max=mu_range_max, + nticks=mu_nticks, + nlevs=mu_nlevs ): + min_frac = 0.55 + min(0, (range_min / (range_max - range_min))) + max_frac = 0.55 + min(0.45, (range_max / (range_max - range_min))) return svariable( dim=4, wrfname="RU_TEND_HADV", @@ -1509,11 +1533,11 @@ def create_UHorizAdvMomentum_at( outfile=f"UHorizAdvMomentum{interpvalue}", interpvar="pressure", interpvalue=interpvalue, - # colormap=cmr.get_sub_cmap("PuOr", min_frac, max_frac, N=nlevs), - # nticks=nticks, - # nlevs=nlevs, - # range_min=range_min, - # range_max=range_max, + colormap=cmr.get_sub_cmap("PuOr", min_frac, max_frac, N=nlevs), + nticks=nticks, + nlevs=nlevs, + range_min=range_min, + range_max=range_max, ) UMassTendency925 = create_UHorizAdvMomentum_at(925) #, range_min=-5, range_max=5) @@ -1521,3 +1545,25 @@ def create_UHorizAdvMomentum_at( UMassTendency700 = create_UHorizAdvMomentum_at(700) #, range_min=-5, range_max=5) UMassTendency500 = create_UHorizAdvMomentum_at(500) #, range_min=-5, range_max=5) UMassTendency300 = create_UHorizAdvMomentum_at(300) #, range_min=-10, range_max=10) + +# QVapor +def create_QVapor_at(interpvalue, range_min=0, range_max=0.01, nticks=11, nlevs=11): + return svariable( + dim=4, + wrfname="QVAPOR", + ptitle=f"Water Vapour Mixing Ratio at {interpvalue} hPa [kg kg-1]", + outfile=f"QVapor{interpvalue}", + interpvar="pressure", + interpvalue=interpvalue, + colormap=get_cmap("YlGnBu"), + nticks=nticks, + nlevs=nlevs, + range_min=range_min, + range_max=range_max, + windbarbs=True, + ) +QVapor925 = create_QVapor_at(925) +QVapor850 = create_QVapor_at(850) +QVapor700 = create_QVapor_at(700) +QVapor500 = create_QVapor_at(500) +QVapor300 = create_QVapor_at(300) From 77659ce9ea039618ed118e90989266aa690bd1a5 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Fri, 21 Aug 2026 16:42:57 +0100 Subject: [PATCH 19/31] feat: first stab at calculating projection momentum tendency terms onto unit wind vectors --- .../wrf_analysis_toolkit/GetSensVar.py | 53 ++++++++++----- .../wrf_analysis_toolkit/utils.py | 66 ++++++++++++++++++- 2 files changed, 103 insertions(+), 16 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index ccce73f..2345a1a 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -4,10 +4,23 @@ from wrf import to_np, getvar, g_geoht, interplevel, destagger import numpy as np +from copy import deepcopy import wrf_analysis_toolkit.SensibleVariables as sv import wrf_analysis_toolkit.Frontogenesis as Frontogenesis +from wrf_analysis_toolkit.utils import destagger_var, project_vector + +MOMENTUM_TEND_DICT = { + "tend_hadv": {"var_u": "ru_tend_hadv", "var_v": "rv_tend_hadv"}, + "tend_vadv": {"var_u": "ru_tend_vadv", "var_v": "ru_tend_vadv"}, + "tend_pgf": {"var_u": "ru_tend_pgf", "var_v": "rv_tend_pgf"}, + "tend_cor": {"var_u": "ru_tend_cor", "var_v": "rv_tend_cor"}, + "tend_curv": {"var_u": "ru_tend_curv", "var_v": "rv_tend_curv"}, + "tendf_pbl": {"var_u": "ru_tendf_pbl", "var_v": "rv_tendf_pbl"}, + "tendf_cu": {"var_u": "ru_tendf_cu", "var_v": "rv_tendf_cu"}, + "tendf_diff": {"var_u": "ru_tendf_diff", "var_v": "rv_tendf_diff"} +} def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): u = v = varv = None @@ -45,23 +58,33 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): F3D = Frontogenesis.frontogenesis3D(ncfile, time) d4var = getvar(ncfile, svariable.interpvar, timeidx=time) d4var.values = F3D + elif any(k in svariable.outfile for k in MOMENTUM_TEND_DICT): + for k in MOMENTUM_TEND_DICT: + if k in svariable.outfile: + tend_name = k + break + print(f"Extracting variables to calculate {tend_name}") + var_u = getvar(ncfile, MOMENTUM_TEND_DICT[tend_name]["var_u"], timeidx=time) + var_u = destagger_var(var_u, meta=False) + var_v = getvar(ncfile, MOMENTUM_TEND_DICT[tend_name]["var_v"], timeidx=time) + var_v = destagger_var(var_v, meta=False) + wind_u = getvar(ncfile, "u", timeidx=time) + wind_u = destagger_var(wind_u, meta=False) + wind_v = getvar(ncfile, "v", timeidx=time) + wind_v = destagger_var(wind_v, meta=False) + wind_spd = getvar(ncfile, "wspd", timeidx=time) + + # Calculate the variable projected onto the unit vector of + # horizontal winds, to calculate the along-flow values + # This is quickest if calculated using arrays without metadata, + # and the metadata are copied from the interpvar afterwards + d4var = deepcopy(interpvar) + print(f"Projecting {tend_name} onto unit wind vector") + d4var.values = project_vector(var_u, var_v, wind_u, wind_v, wind_spd) + d4var.attrs.update(units=var_u.units) # Destagger the variable if it is staggered - stagger_dim = None - for i, dim in enumerate(d4var.dims): - if dim.endswith("_stag"): - stagger_dim = i - print(f"Destaggering {svariable.outfile} along dim {i}") - break - if stagger_dim: - try: - d4var = destagger(d4var, stagger_dim, meta=True) - # Manually assign coordinates from interpvar because these aren't done automatically - d4var = d4var.assign_coords(coords=interpvar.coords) - d4var.attrs.update(stagger=interpvar.attrs['stagger'], coordinates=interpvar.attrs['coordinates']) - d4var["Time"] = interpvar.Time - except: - raise ValueError(f"Unable to destagger {svariable.outfile}") + d4var = destagger_var(d4var, meta_var=interpvar, meta=True) # interpolate variable var = interplevel(d4var, interpvar, svariable.interpvalue) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/utils.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/utils.py index bcb7d14..44cf076 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/utils.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/utils.py @@ -6,7 +6,9 @@ import re from copy import deepcopy from datetime import datetime, timedelta -from wrf import CoordPair, ll_to_xy +from wrf import CoordPair, ll_to_xy, destagger +import numpy as np +from xarray import Dataset, DataArray import wrf_analysis_toolkit.SensibleVariables as sv @@ -200,3 +202,65 @@ def latlon_check(ncfile: Dataset, latlon: tuple): raise ValueError( f"Point ({lat}, {lon}) is outside the WRF domain" ) + +def destagger_var( + var: DataArray, + meta_var: DataArray | None=None, + meta: bool=False +): + stagger_dim = None + for i, dim in enumerate(var.dims): + if dim.endswith("_stag"): + stagger_dim = i + break + + # Destagger the variable if it is staggered + if stagger_dim: + try: + var_out = destagger(var, stagger_dim, meta=meta) + if meta: + if meta_var is None: + raise ValueError("Need a sample meta_var to attatch coordinate fields to destaggared array") + # Manually assign coordinates from meta_var because these aren't done automatically + var_out = var_out.assign_coords(coords=meta_var.coords) + var_out.attrs.update(stagger=meta_var.attrs['stagger'], coordinates=meta_var.attrs['coordinates']) + meta_var["Time"] = meta_var.Time + except: + raise ValueError("Unable to destagger variable") + + # Otherwise return the original variable unchanged + else: + return var + +def project_vector( + var_u: np.ndarray, + var_v: np.ndarray, + wind_u: np.ndarray, + wind_v: np.ndarray, + wind_spd = None, +): + """ + Function to project a given vector (with terms in the X and Y directions) + onto the unit vectors of wind in the X and Y directions (U and V), + in order to calculate the along-flow values of the vector + + Inputs: + - var_u: values of variable of in interest in the x direction, must be destaggered + - var_v: values of variable of in interest in the y direction, must be destaggered + - wind_u: values of wind speed in the x direction, must be destaggered + - wind_v: values of wind speed in the y direction, must be destaggered + - wind_spd: (optional) magnitude of wind spped, will be calculated from vectors if not given + """ + if any([ + var_u.shape() != var_v.shape(), + var_u.shape() != wind_u.shape(), + var_u.shape() != wind_v.shape() + ]): + raise ValueError("project_vector: Shape of vectors do not match, do they need destaggering?") + + if wind_spd is None: + wind_mag = np.sqrt(np.square(wind_u) + np.square(wind_v)) + else: + wind_mag = wind_spd + + return (var_u*wind_u + var_v*wind_v) / wind_mag From 8342617cf38acd7a7b130ef50d640ee87fb9ec43 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Mon, 24 Aug 2026 11:22:14 +0100 Subject: [PATCH 20/31] feat: added sensible variable for TendHADV --- .../wrf_analysis_toolkit/GetSensVar.py | 4 +- .../wrf_analysis_toolkit/SensibleVariables.py | 75 +++++++++++++++---- 2 files changed, 62 insertions(+), 17 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index 2345a1a..4ae8ea2 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -58,9 +58,9 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): F3D = Frontogenesis.frontogenesis3D(ncfile, time) d4var = getvar(ncfile, svariable.interpvar, timeidx=time) d4var.values = F3D - elif any(k in svariable.outfile for k in MOMENTUM_TEND_DICT): + elif any(k in svariable.outfile.lower() for k in MOMENTUM_TEND_DICT): for k in MOMENTUM_TEND_DICT: - if k in svariable.outfile: + if k in svariable.outfile.lower(): tend_name = k break print(f"Extracting variables to calculate {tend_name}") diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py index 266d8c8..c8c159c 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py @@ -1530,10 +1530,31 @@ def create_PotentialVorticity_at( range_max=40, ) +# QVapor +def create_QVapor_at(interpvalue, range_min=0, range_max=0.01, nticks=11, nlevs=11): + return svariable( + dim=4, + wrfname="QVAPOR", + ptitle=f"Water Vapour Mixing Ratio at {interpvalue} hPa [kg kg-1]", + outfile=f"QVapor{interpvalue}", + interpvar="pressure", + interpvalue=interpvalue, + colormap=get_cmap("YlGnBu"), + nticks=nticks, + nlevs=nlevs, + range_min=range_min, + range_max=range_max, + windbarbs=True, + ) +QVapor925 = create_QVapor_at(925) +QVapor850 = create_QVapor_at(850) +QVapor700 = create_QVapor_at(700) +QVapor500 = create_QVapor_at(500) +QVapor300 = create_QVapor_at(300) # Sensible variables for analysing momentum tendency terms - -# Mass Tendency 2D +# Raw variables, in x- or y-direction, not projected onto unit vector of wind +# Mass Tendency 2D, U direction mu_range_min = -100 mu_range_max = 100 mu_max_frac = 0.55 + min(0.45, (pv_range_max / (pv_range_max - pv_range_min))) @@ -1570,31 +1591,55 @@ def create_UHorizAdvMomentum_at( range_min=range_min, range_max=range_max, ) - UMassTendency925 = create_UHorizAdvMomentum_at(925) #, range_min=-5, range_max=5) UMassTendency850 = create_UHorizAdvMomentum_at(850) #, range_min=-5, range_max=5) UMassTendency700 = create_UHorizAdvMomentum_at(700) #, range_min=-5, range_max=5) UMassTendency500 = create_UHorizAdvMomentum_at(500) #, range_min=-5, range_max=5) UMassTendency300 = create_UHorizAdvMomentum_at(300) #, range_min=-10, range_max=10) -# QVapor -def create_QVapor_at(interpvalue, range_min=0, range_max=0.01, nticks=11, nlevs=11): +# Combined terms projected onto unit vector of wind +# MOMENTUM_TEND_DICT = { +# "tend_hadv": {"var_u": "ru_tend_hadv", "var_v": "rv_tend_hadv"}, +# "tend_vadv": {"var_u": "ru_tend_vadv", "var_v": "ru_tend_vadv"}, +# "tend_pgf": {"var_u": "ru_tend_pgf", "var_v": "rv_tend_pgf"}, +# "tend_cor": {"var_u": "ru_tend_cor", "var_v": "rv_tend_cor"}, +# "tend_curv": {"var_u": "ru_tend_curv", "var_v": "rv_tend_curv"}, +# "tendf_pbl": {"var_u": "ru_tendf_pbl", "var_v": "rv_tendf_pbl"}, +# "tendf_cu": {"var_u": "ru_tendf_cu", "var_v": "rv_tendf_cu"}, +# "tendf_diff": {"var_u": "ru_tendf_diff", "var_v": "rv_tendf_diff"} +# } + +def create_TendHADV_at( + interpvalue, + range_min=mu_range_min, + range_max=mu_range_max, + nticks=mu_nticks, + nlevs=mu_nlevs +): + """ + Calculates: + (ru_tend_hadv * U + rv_tend_hadv * V) / |wind_spd| + + GetSensVar works out how to calculate based on outname rather than wrfname + """ + min_frac = 0.55 + min(0, (range_min / (range_max - range_min))) + max_frac = 0.55 + min(0.45, (range_max / (range_max - range_min))) return svariable( dim=4, - wrfname="QVAPOR", - ptitle=f"Water Vapour Mixing Ratio at {interpvalue} hPa [kg kg-1]", - outfile=f"QVapor{interpvalue}", + wrfname=None, + ptitle=f"Horizontal advection of zonal coupled momentum term projected onto unit vector at {interpvalue} hPa [Pa m s-2]", + outfile=f"TendHADV{interpvalue}", interpvar="pressure", interpvalue=interpvalue, - colormap=get_cmap("YlGnBu"), + colormap=cmr.get_sub_cmap("PuOr", min_frac, max_frac, N=nlevs), nticks=nticks, nlevs=nlevs, range_min=range_min, range_max=range_max, - windbarbs=True, ) -QVapor925 = create_QVapor_at(925) -QVapor850 = create_QVapor_at(850) -QVapor700 = create_QVapor_at(700) -QVapor500 = create_QVapor_at(500) -QVapor300 = create_QVapor_at(300) +TendHADV925 = create_TendHADV_at(925) #, range_min=-5, range_max=5) +TendHADV850 = create_TendHADV_at(850) #, range_min=-5, range_max=5) +TendHADV700 = create_TendHADV_at(700) #, range_min=-5, range_max=5) +TendHADV500 = create_TendHADV_at(500) #, range_min=-5, range_max=5) +TendHADV300 = create_TendHADV_at(300) #, range_min=-10, range_max=10) + From d1a35fece3699faf25fc349c0c4b57c748d6adf5 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Mon, 24 Aug 2026 11:30:27 +0100 Subject: [PATCH 21/31] fix: corrected logic for extracting tend variable --- .../wrf_analysis_toolkit/GetSensVar.py | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index 4ae8ea2..fdcd548 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -58,7 +58,7 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): F3D = Frontogenesis.frontogenesis3D(ncfile, time) d4var = getvar(ncfile, svariable.interpvar, timeidx=time) d4var.values = F3D - elif any(k in svariable.outfile.lower() for k in MOMENTUM_TEND_DICT): + elif any([k in svariable.outfile.lower() for k in MOMENTUM_TEND_DICT]): for k in MOMENTUM_TEND_DICT: if k in svariable.outfile.lower(): tend_name = k @@ -68,11 +68,9 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): var_u = destagger_var(var_u, meta=False) var_v = getvar(ncfile, MOMENTUM_TEND_DICT[tend_name]["var_v"], timeidx=time) var_v = destagger_var(var_v, meta=False) - wind_u = getvar(ncfile, "u", timeidx=time) - wind_u = destagger_var(wind_u, meta=False) - wind_v = getvar(ncfile, "v", timeidx=time) - wind_v = destagger_var(wind_v, meta=False) - wind_spd = getvar(ncfile, "wspd", timeidx=time) + ua = getvar(ncfile, "ua", timeidx=time) + va = getvar(ncfile, "va", timeidx=time) + wspd = getvar(ncfile, "wspd", timeidx=time) # Calculate the variable projected onto the unit vector of # horizontal winds, to calculate the along-flow values @@ -80,14 +78,21 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): # and the metadata are copied from the interpvar afterwards d4var = deepcopy(interpvar) print(f"Projecting {tend_name} onto unit wind vector") - d4var.values = project_vector(var_u, var_v, wind_u, wind_v, wind_spd) + d4var.values = project_vector(var_u, var_v, ua, va, wspd) d4var.attrs.update(units=var_u.units) + else: + if svariable.wrfname is not None: + raise ValueError(f"Failed to extract variable {svariable.wrfname}") + else: + raise ValueError(f"Failed to extract variable for {svariable.outname}") + # Destagger the variable if it is staggered d4var = destagger_var(d4var, meta_var=interpvar, meta=True) # interpolate variable var = interplevel(d4var, interpvar, svariable.interpvalue) + # Special variable computation if "AirTempDif6h" in svariable.outfile: # Temperature difference in 6h @@ -101,6 +106,7 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): else: varv = np.append(varprevv[1:], [var.values], axis=0) var.values = var.values - varprevv[0] + elif "AirTempDif12h" in svariable.outfile: # Temperature difference in 12h if varprevv is None: @@ -124,6 +130,7 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): elif svariable.outfile in ["InstRain"]: # InstRain (R) from SimRadarReflectivity1km (dBZ) using Marshall-Palmer: Z = 10^(dBZ/10) = 200*R^1.6 var.values = (0.005 * 10 ** (0.1 * var.values)) ** (0.625) + if windbarbs: # Get wind speed components at interpvalue ua = getvar(ncfile, "ua", timeidx=time) From 787f228b1bb6cfb0a74d8e0638292a971c658791 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Mon, 24 Aug 2026 11:31:58 +0100 Subject: [PATCH 22/31] fix: typo --- wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index fdcd548..7d6c3ce 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -85,7 +85,7 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): if svariable.wrfname is not None: raise ValueError(f"Failed to extract variable {svariable.wrfname}") else: - raise ValueError(f"Failed to extract variable for {svariable.outname}") + raise ValueError(f"Failed to extract variable for {svariable.outfile}") # Destagger the variable if it is staggered d4var = destagger_var(d4var, meta_var=interpvar, meta=True) From d5412309a4a4d7a307b7cc79733323dc7e9c2ca7 Mon Sep 17 00:00:00 2001 From: scottan <33283688+Scottan@users.noreply.github.com> Date: Mon, 24 Aug 2026 13:06:47 +0000 Subject: [PATCH 23/31] fix: started getting TEND_HADV plotting to owkr --- .../wrf_analysis_toolkit/GetSensVar.py | 24 +++++++++++-------- .../wrf_analysis_toolkit/utils.py | 13 ++++++---- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index 7d6c3ce..58665fb 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -12,14 +12,14 @@ from wrf_analysis_toolkit.utils import destagger_var, project_vector MOMENTUM_TEND_DICT = { - "tend_hadv": {"var_u": "ru_tend_hadv", "var_v": "rv_tend_hadv"}, - "tend_vadv": {"var_u": "ru_tend_vadv", "var_v": "ru_tend_vadv"}, - "tend_pgf": {"var_u": "ru_tend_pgf", "var_v": "rv_tend_pgf"}, - "tend_cor": {"var_u": "ru_tend_cor", "var_v": "rv_tend_cor"}, - "tend_curv": {"var_u": "ru_tend_curv", "var_v": "rv_tend_curv"}, - "tendf_pbl": {"var_u": "ru_tendf_pbl", "var_v": "rv_tendf_pbl"}, - "tendf_cu": {"var_u": "ru_tendf_cu", "var_v": "rv_tendf_cu"}, - "tendf_diff": {"var_u": "ru_tendf_diff", "var_v": "rv_tendf_diff"} + "tendhadv": {"var_u": "RU_TEND_HADV", "var_v": "RV_TEND_HADV"}, + "tendvadv": {"var_u": "RU_TEND_VADV", "var_v": "RU_TEND_VADV"}, + "tendpgf": {"var_u": "RU_TEND_PGF", "var_v": "RU_TEND_PGF"}, + "tendcor": {"var_u": "RU_TEND_COR", "var_v": "RU_TEND_COR"}, + "tendcurv": {"var_u": "RU_TEND_CURV", "var_v": "RU_TEND_CURV"}, + "tendfpbl": {"var_u": "RU_TENDF_PBL", "var_v": "RU_TENDF_PBL"}, + "tendfcu": {"var_u": "RU_TENDF_CU", "var_v": "RU_TENDF_CU"}, + "tendfdiff": {"var_u": "RU_TENDF_DIFF", "var_v": "RU_TENDF_DIFF"} } def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): @@ -45,9 +45,10 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): # Converts accumulated rain to "hourly" rain (given hourly time indices) if varprevv is not None: var.values = var.values - varprevv - + # For 3D +value variables, interpolated at interpvalue of interpvar elif svariable.dim == 4: + interpvar = getvar(ncfile, svariable.interpvar, timeidx=time) if svariable.wrfname is not None: d4var = getvar(ncfile, svariable.wrfname, timeidx=time) @@ -65,6 +66,8 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): break print(f"Extracting variables to calculate {tend_name}") var_u = getvar(ncfile, MOMENTUM_TEND_DICT[tend_name]["var_u"], timeidx=time) + attrs = var_u.attrs + print(attrs) var_u = destagger_var(var_u, meta=False) var_v = getvar(ncfile, MOMENTUM_TEND_DICT[tend_name]["var_v"], timeidx=time) var_v = destagger_var(var_v, meta=False) @@ -79,7 +82,8 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): d4var = deepcopy(interpvar) print(f"Projecting {tend_name} onto unit wind vector") d4var.values = project_vector(var_u, var_v, ua, va, wspd) - d4var.attrs.update(units=var_u.units) + d4var.attrs.update(attrs) + print(d4var) else: if svariable.wrfname is not None: diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/utils.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/utils.py index 44cf076..75cc9bd 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/utils.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/utils.py @@ -224,10 +224,13 @@ def destagger_var( # Manually assign coordinates from meta_var because these aren't done automatically var_out = var_out.assign_coords(coords=meta_var.coords) var_out.attrs.update(stagger=meta_var.attrs['stagger'], coordinates=meta_var.attrs['coordinates']) - meta_var["Time"] = meta_var.Time + var_out["Time"] = meta_var.Time + + return var_out + except: raise ValueError("Unable to destagger variable") - + # Otherwise return the original variable unchanged else: return var @@ -252,9 +255,9 @@ def project_vector( - wind_spd: (optional) magnitude of wind spped, will be calculated from vectors if not given """ if any([ - var_u.shape() != var_v.shape(), - var_u.shape() != wind_u.shape(), - var_u.shape() != wind_v.shape() + var_u.shape != var_v.shape, + var_u.shape != wind_u.shape, + var_u.shape != wind_v.shape ]): raise ValueError("project_vector: Shape of vectors do not match, do they need destaggering?") From 12ebdcbae9bd5549c8c0b24f6bbabf90778aed58 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Mon, 24 Aug 2026 14:16:27 +0100 Subject: [PATCH 24/31] fix: changed default scale for tend fields --- .../wrf_analysis_toolkit/SensibleVariables.py | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py index c8c159c..3ab284d 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py @@ -1608,13 +1608,31 @@ def create_UHorizAdvMomentum_at( # "tendf_cu": {"var_u": "ru_tendf_cu", "var_v": "rv_tendf_cu"}, # "tendf_diff": {"var_u": "ru_tendf_diff", "var_v": "rv_tendf_diff"} # } +tend_scale="bounds", +tend_bounds=[-100, -50, -20, -10, -5, 5, 10, 20, 50, 100], +tend_colormap=ListedColormap( + [ + "darkgreen", + "forestgreen", + "limegreen", + "greenyellow", + "white", + "gold", + "darkorange", + "red", + "darkred", + ] +), +tend_range_min=-100, +tend_range_max=100, def create_TendHADV_at( interpvalue, - range_min=mu_range_min, - range_max=mu_range_max, - nticks=mu_nticks, - nlevs=mu_nlevs + scale=tend_scale, + bounds=tend_bounds, + colormap=tend_colormap, + range_min=tend_range_min, + range_max=tend_range_max ): """ Calculates: @@ -1622,8 +1640,6 @@ def create_TendHADV_at( GetSensVar works out how to calculate based on outname rather than wrfname """ - min_frac = 0.55 + min(0, (range_min / (range_max - range_min))) - max_frac = 0.55 + min(0.45, (range_max / (range_max - range_min))) return svariable( dim=4, wrfname=None, @@ -1631,9 +1647,9 @@ def create_TendHADV_at( outfile=f"TendHADV{interpvalue}", interpvar="pressure", interpvalue=interpvalue, - colormap=cmr.get_sub_cmap("PuOr", min_frac, max_frac, N=nlevs), - nticks=nticks, - nlevs=nlevs, + scale=scale, + bounds=bounds, + colormap=colormap, range_min=range_min, range_max=range_max, ) From 6b1b5d2c3657765b5ad43c637f4498a15121ded9 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Mon, 24 Aug 2026 14:21:21 +0100 Subject: [PATCH 25/31] fix: syntax --- .../wrf_analysis_toolkit/SensibleVariables.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py index 3ab284d..c267060 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py @@ -1609,7 +1609,7 @@ def create_UHorizAdvMomentum_at( # "tendf_diff": {"var_u": "ru_tendf_diff", "var_v": "rv_tendf_diff"} # } tend_scale="bounds", -tend_bounds=[-100, -50, -20, -10, -5, 5, 10, 20, 50, 100], +tend_bounds=[-100, -50, -20, -10, -5, 5, 10, 20, 50, 100] tend_colormap=ListedColormap( [ "darkgreen", @@ -1622,9 +1622,9 @@ def create_UHorizAdvMomentum_at( "red", "darkred", ] -), -tend_range_min=-100, -tend_range_max=100, +) +tend_range_min=-100 +tend_range_max=100 def create_TendHADV_at( interpvalue, @@ -1653,6 +1653,7 @@ def create_TendHADV_at( range_min=range_min, range_max=range_max, ) + TendHADV925 = create_TendHADV_at(925) #, range_min=-5, range_max=5) TendHADV850 = create_TendHADV_at(850) #, range_min=-5, range_max=5) TendHADV700 = create_TendHADV_at(700) #, range_min=-5, range_max=5) From 52dbc79a135ddc9ed47f95504819829b81b3dd2b Mon Sep 17 00:00:00 2001 From: scottan <33283688+Scottan@users.noreply.github.com> Date: Mon, 24 Aug 2026 13:31:44 +0000 Subject: [PATCH 26/31] fix: fixing plotting of scale for tend_hadv --- wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py | 3 +-- .../wrf_analysis_toolkit/SensibleVariables.py | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index 58665fb..484fe3c 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -67,7 +67,6 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): print(f"Extracting variables to calculate {tend_name}") var_u = getvar(ncfile, MOMENTUM_TEND_DICT[tend_name]["var_u"], timeidx=time) attrs = var_u.attrs - print(attrs) var_u = destagger_var(var_u, meta=False) var_v = getvar(ncfile, MOMENTUM_TEND_DICT[tend_name]["var_v"], timeidx=time) var_v = destagger_var(var_v, meta=False) @@ -83,7 +82,7 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): print(f"Projecting {tend_name} onto unit wind vector") d4var.values = project_vector(var_u, var_v, ua, va, wspd) d4var.attrs.update(attrs) - print(d4var) + print(d4var.attrs) else: if svariable.wrfname is not None: diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py index c267060..b980829 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py @@ -1608,9 +1608,9 @@ def create_UHorizAdvMomentum_at( # "tendf_cu": {"var_u": "ru_tendf_cu", "var_v": "rv_tendf_cu"}, # "tendf_diff": {"var_u": "ru_tendf_diff", "var_v": "rv_tendf_diff"} # } -tend_scale="bounds", -tend_bounds=[-100, -50, -20, -10, -5, 5, 10, 20, 50, 100] -tend_colormap=ListedColormap( +tend_scale = "bounds" +tend_bounds = [-100, -50, -20, -10, -5, 5, 10, 20, 50, 100] +tend_colormap = ListedColormap( [ "darkgreen", "forestgreen", @@ -1638,7 +1638,7 @@ def create_TendHADV_at( Calculates: (ru_tend_hadv * U + rv_tend_hadv * V) / |wind_spd| - GetSensVar works out how to calculate based on outname rather than wrfname + GetSensVar works out what to calculate based on outname rather than wrfname """ return svariable( dim=4, From 23c4bb23a3db56a1b521608e3d85f6acce8521bb Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Mon, 24 Aug 2026 14:34:02 +0100 Subject: [PATCH 27/31] fix: tweaked scale for TEND_HADV --- .../wrf_analysis_toolkit/SensibleVariables.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py index b980829..f4b89ce 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py @@ -1609,22 +1609,22 @@ def create_UHorizAdvMomentum_at( # "tendf_diff": {"var_u": "ru_tendf_diff", "var_v": "rv_tendf_diff"} # } tend_scale = "bounds" -tend_bounds = [-100, -50, -20, -10, -5, 5, 10, 20, 50, 100] +tend_bounds = [-200, -100, -50, -25, 25, 50, 100, 200] tend_colormap = ListedColormap( [ - "darkgreen", - "forestgreen", - "limegreen", - "greenyellow", - "white", - "gold", - "darkorange", - "red", "darkred", + "red", + "darkorange", + "gold", + "white", + "greenyellow", + "limegreen", + "forestgreen", + "darkgreen", ] ) -tend_range_min=-100 -tend_range_max=100 +tend_range_min=-200 +tend_range_max=200 def create_TendHADV_at( interpvalue, From 8ec0800608fe88bac59e06686fa7cd55dc995173 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Mon, 24 Aug 2026 14:54:52 +0100 Subject: [PATCH 28/31] feat: added sensible variables for all tend momentum terms --- .../wrf_analysis_toolkit/SensibleVariables.py | 199 ++++++++++++++++++ 1 file changed, 199 insertions(+) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py index f4b89ce..b53bf71 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py @@ -1660,3 +1660,202 @@ def create_TendHADV_at( TendHADV500 = create_TendHADV_at(500) #, range_min=-5, range_max=5) TendHADV300 = create_TendHADV_at(300) #, range_min=-10, range_max=10) + + +def create_TendVADV_at( + interpvalue, + scale=tend_scale, + bounds=tend_bounds, + colormap=tend_colormap, + range_min=tend_range_min, + range_max=tend_range_max +): + return svariable( + dim=4, + wrfname=None, + ptitle=f"Vertical advection of zonal coupled momentum term projected onto unit vector at {interpvalue} hPa [Pa m s-2]", + outfile=f"TendVADV{interpvalue}", + interpvar="pressure", + interpvalue=interpvalue, + scale=scale, + bounds=bounds, + colormap=colormap, + range_min=range_min, + range_max=range_max, + ) + +TendVADV925 = create_TendVADV_at(925) #, range_min=-5, range_max=5) +TendVADV850 = create_TendVADV_at(850) #, range_min=-5, range_max=5) +TendVADV700 = create_TendVADV_at(700) #, range_min=-5, range_max=5) +TendVADV500 = create_TendVADV_at(500) #, range_min=-5, range_max=5) +TendVADV300 = create_TendVADV_at(300) #, range_min=-10, range_max=10) + +def create_TendPGF_at( + interpvalue, + scale=tend_scale, + bounds=tend_bounds, + colormap=tend_colormap, + range_min=tend_range_min, + range_max=tend_range_max +): + return svariable( + dim=4, + wrfname=None, + ptitle=f"Pressure Gradient Force zonal coupled momentum term projected onto unit vector at {interpvalue} hPa [Pa m s-2]", + outfile=f"TendPGF{interpvalue}", + interpvar="pressure", + interpvalue=interpvalue, + scale=scale, + bounds=bounds, + colormap=colormap, + range_min=range_min, + range_max=range_max, + ) + +TendPGF925 = create_TendPGF_at(925) #, range_min=-5, range_max=5) +TendPGF850 = create_TendPGF_at(850) #, range_min=-5, range_max=5) +TendPGF700 = create_TendPGF_at(700) #, range_min=-5, range_max=5) +TendPGF500 = create_TendPGF_at(500) #, range_min=-5, range_max=5) +TendPGF300 = create_TendPGF_at(300) #, range_min=-10, range_max=10) + +def create_TendCOR_at( + interpvalue, + scale=tend_scale, + bounds=tend_bounds, + colormap=tend_colormap, + range_min=tend_range_min, + range_max=tend_range_max +): + return svariable( + dim=4, + wrfname=None, + ptitle=f"Coriolis zonal coupled momentum term projected onto unit vector at {interpvalue} hPa [Pa m s-2]", + outfile=f"TendCOR{interpvalue}", + interpvar="pressure", + interpvalue=interpvalue, + scale=scale, + bounds=bounds, + colormap=colormap, + range_min=range_min, + range_max=range_max, + ) + +TendCOR925 = create_TendCOR_at(925) #, range_min=-5, range_max=5) +TendCOR850 = create_TendCOR_at(850) #, range_min=-5, range_max=5) +TendCOR700 = create_TendCOR_at(700) #, range_min=-5, range_max=5) +TendCOR500 = create_TendCOR_at(500) #, range_min=-5, range_max=5) +TendCOR300 = create_TendCOR_at(300) #, range_min=-10, range_max=10) + +def create_TendCURV_at( + interpvalue, + scale=tend_scale, + bounds=tend_bounds, + colormap=tend_colormap, + range_min=tend_range_min, + range_max=tend_range_max +): + return svariable( + dim=4, + wrfname=None, + ptitle=f"Curvature zonal coupled momentum term projected onto unit vector at {interpvalue} hPa [Pa m s-2]", + outfile=f"TendCURV{interpvalue}", + interpvar="pressure", + interpvalue=interpvalue, + scale=scale, + bounds=bounds, + colormap=colormap, + range_min=range_min, + range_max=range_max, + ) + +TendCURV925 = create_TendCURV_at(925) #, range_min=-5, range_max=5) +TendCURV850 = create_TendCURV_at(850) #, range_min=-5, range_max=5) +TendCURV700 = create_TendCURV_at(700) #, range_min=-5, range_max=5) +TendCURV500 = create_TendCURV_at(500) #, range_min=-5, range_max=5) +TendCURV300 = create_TendCURV_at(300) #, range_min=-10, range_max=10) + + +def create_TendfPBL_at( + interpvalue, + scale=tend_scale, + bounds=tend_bounds, + colormap=tend_colormap, + range_min=tend_range_min, + range_max=tend_range_max +): + return svariable( + dim=4, + wrfname=None, + ptitle=f"PBL coupled momentum term projected onto unit vector at {interpvalue} hPa [Pa m s-2]", + outfile=f"TendfPBL{interpvalue}", + interpvar="pressure", + interpvalue=interpvalue, + scale=scale, + bounds=bounds, + colormap=colormap, + range_min=range_min, + range_max=range_max, + ) + +TendfPBL925 = create_TendfPBL_at(925) #, range_min=-5, range_max=5) +TendfPBL850 = create_TendfPBL_at(850) #, range_min=-5, range_max=5) +TendfPBL700 = create_TendfPBL_at(700) #, range_min=-5, range_max=5) +TendfPBL500 = create_TendfPBL_at(500) #, range_min=-5, range_max=5) +TendfPBL300 = create_TendfPBL_at(300) #, range_min=-10, range_max=10) + +def create_TendfCU_at( + interpvalue, + scale=tend_scale, + bounds=tend_bounds, + colormap=tend_colormap, + range_min=tend_range_min, + range_max=tend_range_max +): + return svariable( + dim=4, + wrfname=None, + ptitle=f"Microphysics coupled momentum term projected onto unit vector at {interpvalue} hPa [Pa m s-2]", + outfile=f"TendfCU{interpvalue}", + interpvar="pressure", + interpvalue=interpvalue, + scale=scale, + bounds=bounds, + colormap=colormap, + range_min=range_min, + range_max=range_max, + ) + +TendfCU925 = create_TendfCU_at(925) #, range_min=-5, range_max=5) +TendfCU850 = create_TendfCU_at(850) #, range_min=-5, range_max=5) +TendfCU700 = create_TendfCU_at(700) #, range_min=-5, range_max=5) +TendfCU500 = create_TendfCU_at(500) #, range_min=-5, range_max=5) +TendfCU300 = create_TendfCU_at(300) #, range_min=-10, range_max=10) + +def create_TendfDIFF_at( + interpvalue, + scale=tend_scale, + bounds=tend_bounds, + colormap=tend_colormap, + range_min=tend_range_min, + range_max=tend_range_max +): + return svariable( + dim=4, + wrfname=None, + ptitle=f"Diffusion coupled momentum term projected onto unit vector at {interpvalue} hPa [Pa m s-2]", + outfile=f"TendfDIFF{interpvalue}", + interpvar="pressure", + interpvalue=interpvalue, + scale=scale, + bounds=bounds, + colormap=colormap, + range_min=range_min, + range_max=range_max, + ) + +TendfDIFF925 = create_TendfDIFF_at(925) #, range_min=-5, range_max=5) +TendfDIFF850 = create_TendfDIFF_at(850) #, range_min=-5, range_max=5) +TendfDIFF700 = create_TendfDIFF_at(700) #, range_min=-5, range_max=5) +TendfDIFF500 = create_TendfDIFF_at(500) #, range_min=-5, range_max=5) +TendfDIFF300 = create_TendfDIFF_at(300) #, range_min=-10, range_max=10) + From 9abe45d031ff5c0fec02024a4011fd6b3990de53 Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Mon, 24 Aug 2026 14:57:11 +0100 Subject: [PATCH 29/31] fix: tweak to scales --- .../wrf_analysis_toolkit/SensibleVariables.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py index b53bf71..ebaca77 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py @@ -1609,7 +1609,7 @@ def create_UHorizAdvMomentum_at( # "tendf_diff": {"var_u": "ru_tendf_diff", "var_v": "rv_tendf_diff"} # } tend_scale = "bounds" -tend_bounds = [-200, -100, -50, -25, 25, 50, 100, 200] +tend_bounds = [-400, -200, -100, -50, -25, 25, 50, 100, 200, 400] tend_colormap = ListedColormap( [ "darkred", @@ -1623,8 +1623,8 @@ def create_UHorizAdvMomentum_at( "darkgreen", ] ) -tend_range_min=-200 -tend_range_max=200 +tend_range_min=-400 +tend_range_max=400 def create_TendHADV_at( interpvalue, From 3a1cd9fc73a346e32a4a5618b8ce5e21198411fa Mon Sep 17 00:00:00 2001 From: Scott Archer-Nicholls Date: Mon, 24 Aug 2026 14:58:55 +0100 Subject: [PATCH 30/31] tyle: code tidy --- wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py index 484fe3c..c98bf1c 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/GetSensVar.py @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: apache-2.0 -from wrf import to_np, getvar, g_geoht, interplevel, destagger +from wrf import to_np, getvar, g_geoht, interplevel import numpy as np from copy import deepcopy @@ -82,7 +82,6 @@ def GetSensVar(ncfile, svariable, windbarbs=0, time=0, varprevv=None): print(f"Projecting {tend_name} onto unit wind vector") d4var.values = project_vector(var_u, var_v, ua, va, wspd) d4var.attrs.update(attrs) - print(d4var.attrs) else: if svariable.wrfname is not None: From 8098005ee1b362c5556dbd947937f29a1717bf09 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 24 Aug 2026 14:14:29 +0000 Subject: [PATCH 31/31] Add License and Copyright Headers --- wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py index ebaca77..c572a7f 100644 --- a/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py +++ b/wrf_analysis_toolkit/wrf_analysis_toolkit/SensibleVariables.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: 2026 University of Manchester -#4 +# # SPDX-License-Identifier: apache-2.0 from matplotlib.pyplot import get_cmap