Repository navigation
Spectral and Newtonian Nudging #670
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
James Bruten (james-bruten-mo)
merged 39 commits into
MetOffice:main
from
tommbendall:spectral_nudging
Oct 22, 2026
Merged
Changes from 25 commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
4a7b1fc
Merge pull request #5 from MetOffice/stable
tommbendall 92ac379
Merge pull request #13 from MetOffice/stable
tommbendall cba11c0
bring across spectral nudging changes
tommbendall 8d14f6d
remove nudging_source, fix various bugs and get azspice suite running
tommbendall c929801
rose meta tweak
tommbendall 54864ec
attempt to improve upgrade macro
tommbendall bf37c8e
another attempt to fix upgrade macro
tommbendall cde3772
final upgrade macro
tommbendall 96e903f
be neater with check on nudging config
tommbendall 00198e4
actually get upgrade macro working properly
tommbendall b3edeee
tidy up so that multires_coupling is not necessary for nudging
tommbendall 6d4e907
protect physics settings and fix upgrade macro
tommbendall 3e84f8f
... and fix another rogue config variable
tommbendall 13ae8ee
rose-meta fix
tommbendall 7f291c5
further clean up of handling config
tommbendall 0e5e312
remove defunct kgos
tommbendall a45c0ff
fix convolution weights kernel
tommbendall d98e02d
add new namelist option and tweak convolution
tommbendall bb03d05
fix bug in weights
tommbendall 1ed52ce
rejig vertical nudging weights
tommbendall dc7d83b
fix fail-ifs
tommbendall d637e70
(hopefully) final renaming of some namelist variables and fix a couple
tommbendall b71d223
adjust default and optional namelist values
tommbendall bcd8fe9
adjust envelope width
tommbendall e5a2430
add documentation
tommbendall b921763
big rewrite: reorganise options, vertical weights are 1D array, use
tommbendall bd61626
fix tropopause api
tommbendall e27c91f
remove old option
tommbendall c4c2c3b
use appropriate theta/exner for locating tropopause
tommbendall b5a2b9c
rose config-dump and add ifdef to nudging_alg to avoid unused variable
tommbendall d5913f1
fix silly error with nudging levels
tommbendall 70583da
fix temporal and vertical weights
tommbendall 05797a3
add missing doxygen comment
tommbendall 9f2b508
more science review changes
tommbendall a1815c5
code review comments
tommbendall 7241098
Merge remote-tracking branch 'upstream/main' into spectral_nudging
tommbendall fa2fd3c
Merge branch 'main' into spectral_nudging
james-bruten-mo 2f21f16
apply macros
james-bruten-mo 2f8223b
update kgos
james-bruten-mo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
193 changes: 193 additions & 0 deletions
193
documentation/source/science_guide/nudging/convolution.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,193 @@ | ||
| .. ----------------------------------------------------------------------------- | ||
| (c) Crown copyright Met Office. All rights reserved. | ||
| The file LICENCE, distributed with this code, contains details of the terms | ||
| under which the code may be used. | ||
| ----------------------------------------------------------------------------- | ||
| .. _nudging_science_convolution: | ||
|
|
||
| Filtering by Convolution | ||
| ======================== | ||
|
|
||
| The convolution method (see :ref:`nudging_science_formulation_convolution`) | ||
| applies a scale-selective filter :math:`\mathcal{L}` to the difference | ||
| between the model field and the reference field, so that only the large | ||
| scales are nudged. This section explains why the filter is applied as a | ||
| convolution in physical space, and derives the convolution kernel used on | ||
| the sphere. | ||
|
|
||
| Consider filtering a field :math:`f` so that only its large scales are | ||
| retained. Writing the spectrum of :math:`f` as :math:`\mathcal{F}[f]`, | ||
| where :math:`\mathcal{F}` denotes a transform to spectral space, the filter | ||
| :math:`\mathcal{L}` acts as a multiplication of the spectrum by a function | ||
| :math:`\ell` that varies with wavenumber: | ||
|
|
||
| .. math:: :label: eq:nudging_spectral_filter | ||
|
|
||
| \mathcal{L}[f] = \mathcal{F}^{-1}\left[ \ell \; \mathcal{F}[f] \right] . | ||
|
|
||
| It is vital that :math:`\ell` does not amplify any wavenumbers, which will | ||
| cause the numerical model to go unstable. However, it is not always | ||
| necessary for an analytic form of :math:`\ell` to be preserved | ||
| exactly by the discretisation. For example, an idealised "top-hat" may be | ||
| specified for :math:`\ell`, but it may be acceptable for the discretisation to | ||
| only approximate this. | ||
|
|
||
| Why a convolution? | ||
| ------------------ | ||
|
|
||
| The most direct way to apply :eq:`eq:nudging_spectral_filter` would be to | ||
| transform :math:`f` to spectral space, multiply by :math:`\ell`, and | ||
| transform back. However, for a parallel implementation in which :math:`f` | ||
| is distributed geographically across many processors, this is very | ||
| inefficient: the transform requires global gather and scatter | ||
| communications and/or global summations, whose cost grows exponentially | ||
| with the number of processors. | ||
|
|
||
| An alternative is to note the convolution theorem: the spectrum of a | ||
| convolved field is the product of the spectra of the field and of the | ||
| convolving function. Defining the convolution of :math:`f` with a function | ||
| :math:`c` as | ||
|
|
||
| .. math:: :label: eq:nudging_convolution_def | ||
|
|
||
| \mathcal{C}[f, c] := \int_\Omega f(\boldsymbol{y}) \; c(\boldsymbol{y} - \boldsymbol{x}) \; \mathrm{d}\boldsymbol{y} \equiv f \ast c , | ||
|
|
||
| the convolution theorem gives | ||
| :math:`\mathcal{F}\!\left[\mathcal{C}[f, c]\right] = \mathcal{F}[f] \, | ||
| \mathcal{F}[c]`. Since the filter :eq:`eq:nudging_spectral_filter` acts as a | ||
| multiplication in spectral space, it can therefore be applied as a | ||
| convolution in physical space, provided the convolving function is chosen so | ||
| that :math:`\mathcal{F}[c] = \ell`, i.e. :math:`c = \mathcal{F}^{-1}[\ell]`. | ||
|
|
||
| The key advantage is that, if :math:`c` has compact support, the integral in | ||
| :eq:`eq:nudging_convolution_def` reduces to an integral over a local | ||
| neighbourhood of each point. On a distributed mesh this requires only | ||
| communication of neighbouring data through *halo exchanges*, rather than the | ||
| global communications demanded by a spectral transform. | ||
|
|
||
| In practice the convolution is truncated by restricting it to a local | ||
| stencil of finite extent. The truncated kernel is no longer exactly equal to | ||
| :math:`\mathcal{F}^{-1}[\ell]`, but can remain a good approximation provided | ||
| the truncation occurs where :math:`c` is already small. When the nudging of | ||
| the spectrum does not need to be exact, this can be acceptable. | ||
|
|
||
| The filter on the sphere | ||
| ------------------------ | ||
|
|
||
| To apply this approach on the cubed-sphere, the convolution kernel must be | ||
| derived for the sphere. The cubed-sphere is non-orthogonal and has | ||
| discontinuities at panel edges, which makes a separable | ||
| longitude--latitude Fourier filter challenging. Instead, the field is | ||
| expanded in spherical harmonics, which are appropriate for quasi-uniform | ||
| meshes of the sphere. This use of a convolution for scale-selective | ||
| filtering on a cubed-sphere follows the approach of Thatcher and McGregor | ||
| (2009). | ||
|
|
||
| The spherical harmonics, as functions of co-latitude :math:`\theta` and | ||
| longitude :math:`\varphi`, may be written as | ||
|
|
||
| .. math:: :label: eq:nudging_spherical_harmonic | ||
|
|
||
| Y_{lm}(\theta, \varphi) = N_{lm} \, e^{i m \varphi} \, P_{lm}(\cos\theta) , | ||
|
|
||
| where :math:`P_{lm}` are the associated Legendre polynomials and | ||
| :math:`N_{lm}` is a normalisation chosen so that the :math:`Y_{lm}` are | ||
| orthonormal over the sphere. A field :math:`f` is expanded as | ||
| :math:`f(\theta,\varphi) = \sum_{l,m} a_{lm} Y_{lm}(\theta,\varphi)`. | ||
|
|
||
| We seek the convolution kernel :math:`c` that retains only the spherical | ||
| harmonic components with total wavenumber between :math:`k_{min}` and | ||
| :math:`k_{max}`. Since the spherical harmonics form an orthonormal basis, | ||
| this filter kernel can be written | ||
|
|
||
| .. math:: :label: eq:nudging_general_kernel | ||
|
|
||
| c(\theta,\varphi,\theta',\varphi') = | ||
| \sum_{l=k_{min}}^{k_{max}} \sum_{m=-l}^{l} | ||
| F_{lm} \, Y_{lm}(\theta,\varphi) \, Y_{lm}^{\ast}(\theta',\varphi') . | ||
|
|
||
| The kernel should depend only on the distance between two points, and not on | ||
| their orientation. This requires that there is no dependence on :math:`m` or | ||
| :math:`\varphi`, so that :math:`F_{lm} = F_{l0}`. The sum over :math:`m` can | ||
| then be carried out using the spherical harmonic addition theorem, | ||
|
|
||
| .. math:: :label: eq:nudging_addition_theorem | ||
|
|
||
| \sum_{m=-l}^{l} Y_{lm}(\theta,\varphi) \, Y_{lm}^{\ast}(\theta',\varphi') | ||
| = \frac{2l+1}{4\pi} \, P_l\!\left(\cos\gamma\right) , | ||
|
|
||
| where :math:`P_l` is the Legendre polynomial of degree :math:`l` and | ||
| :math:`\gamma` is the great-circle (central) angle between the two points. | ||
| Taking an idealised top-hat filter in spectral space, :math:`F_{l0} = 1`, | ||
| the kernel becomes a weighted sum of Legendre polynomials of the central | ||
| angle: | ||
|
|
||
| .. math:: :label: eq:nudging_kernel | ||
|
|
||
| c(\gamma) = \sum_{l=k_{min}}^{k_{max}} \frac{2l+1}{4\pi} \, P_l(\cos\gamma) . | ||
|
|
||
| The Legendre polynomials may be evaluated efficiently using the recurrence | ||
| relation | ||
|
|
||
| .. math:: :label: eq:nudging_legendre_recurrence | ||
|
|
||
| \begin{aligned} | ||
| P_0(\cos\gamma) &= 1 , \\ | ||
| P_1(\cos\gamma) &= \cos\gamma , \\ | ||
| P_l(\cos\gamma) &= \frac{2l-1}{l} \cos\gamma \, P_{l-1}(\cos\gamma) | ||
| - \frac{l-1}{l} \, P_{l-2}(\cos\gamma) . | ||
| \end{aligned} | ||
|
|
||
| Equation :eq:`eq:nudging_kernel` is the kernel that corresponds exactly to | ||
| the idealised top-hat spectral filter. It resembles a :math:`\mathrm{sinc}` | ||
| function, (mainly!) decaying away from :math:`\gamma = 0`, and is evaluated at the | ||
| points of the stencil surrounding each grid point to give the discrete | ||
| convolution weights. | ||
|
|
||
| Convolution Envelope | ||
| -------------------- | ||
|
|
||
| However the series of Legendre polynomials does not strictly have compact support | ||
| and extends over the whole sphere. An accurate convolution would therefore | ||
| require a stencil covering the whole domain. | ||
|
|
||
| Instead we truncate the filter to a local stencil. To avoid the spurious | ||
| amplification of any wavenumbers, the filter is multiplied by a Gaussian | ||
| envelope that decays to zero towards the edge of the stencil. The width of | ||
| this envelope is a configurable parameter of the scheme, and must be chosen | ||
| together with the stencil extent (see :ref:`nudging_user_index` for | ||
| guidance). | ||
|
|
||
| Thus the actual filter used is | ||
|
|
||
| .. math:: :label: eq:nudging_enveloped_kernel | ||
|
|
||
| c(\gamma) = \left[ \sum_{l=k_{min}}^{k_{max}} \frac{2l+1}{4\pi} | ||
| P_l(\cos\gamma) \right] | ||
| \exp\left[ -\frac{1}{2} \left( \frac{\gamma}{\sigma} \right)^2 \right] , | ||
|
|
||
| where :math:`\gamma` is the great-circle angle from the central point and | ||
| :math:`\sigma` is the width of the Gaussian envelope. | ||
|
|
||
| :numref:`fig_nudging_envelope` illustrates the effect of the envelope. The | ||
| underlying Legendre filter :eq:`eq:nudging_kernel` oscillates and decays only | ||
| slowly with distance, so that it does not have compact support. Multiplying | ||
| by the Gaussian envelope gives the enveloped filter, which decays smoothly to | ||
| zero well within the stencil, allowing the convolution to be truncated to a | ||
| local region with minimal error, provided the stencil is wide enough for the | ||
| envelope to have decayed sufficiently by its edge. | ||
|
|
||
| .. _fig_nudging_envelope: | ||
|
|
||
| .. figure:: legendre_envelope_convolution_filter.svg | ||
| :width: 90% | ||
| :align: center | ||
|
|
||
| The spherical-harmonic convolution filter for a top-hat retaining total | ||
| wavenumbers from :math:`k_{min} = 2` to :math:`k_{max} = 20`, plotted | ||
| against great-circle distance. The underlying Legendre filter | ||
| (black dashed, :eq:`eq:nudging_kernel`) oscillates and decays only slowly, | ||
| whereas the enveloped filter (blue, :eq:`eq:nudging_enveloped_kernel`) | ||
| decays smoothly to zero. The red circles show the discrete filter values | ||
| sampled at the stencil points for a stencil of depth 12 on a C56 mesh. | ||
|
|
101 changes: 101 additions & 0 deletions
101
documentation/source/science_guide/nudging/formulation.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| .. ----------------------------------------------------------------------------- | ||
| (c) Crown copyright Met Office. All rights reserved. | ||
| The file LICENCE, distributed with this code, contains details of the terms | ||
| under which the code may be used. | ||
| ----------------------------------------------------------------------------- | ||
| .. _nudging_science_formulation: | ||
|
|
||
| Formulation | ||
| =========== | ||
|
|
||
| Let :math:`X` denote a field being nudged (potential temperature | ||
| :math:`\theta`, or one of the horizontal wind components :math:`u`, :math:`v`), | ||
| and let :math:`X_{ref}` denote the corresponding reference field, having | ||
| already been vertically interpolated onto the model's levels (see | ||
| :ref:`nudging_science_vertical_treatment`). At each call to the nudging | ||
| scheme, an increment :math:`\Delta X` is calculated and added to the | ||
| model's tendency for :math:`X`. | ||
|
|
||
| Two methods are available for calculating :math:`\Delta X`. | ||
|
|
||
| .. _nudging_science_formulation_newtonian: | ||
|
|
||
| Newtonian relaxation | ||
| --------------------- | ||
|
|
||
| In Newtonian relaxation, the increment is simply proportional to the local | ||
| difference between the field and its reference value: | ||
|
|
||
| .. math:: :label: eq:nudging_newtonian | ||
|
|
||
| \Delta X = w \left( X_{ref} - X \right) | ||
|
|
||
| where :math:`w` is a weight described in :ref:`nudging_science_weights` | ||
| below. This relaxes :math:`X` directly towards :math:`X_{ref}` at every | ||
| horizontal scale present in the reference data, with no spectral | ||
| selectivity. | ||
|
|
||
| .. _nudging_science_formulation_convolution: | ||
|
|
||
| Convolution | ||
| ----------- | ||
|
|
||
| In the convolution method, the local difference between the field and its | ||
| reference value is first filtered so that only the large scales are | ||
| retained, before being scaled by the same weight :math:`w`: | ||
|
|
||
| .. math:: :label: eq:nudging_convolution | ||
|
|
||
| \Delta X = w \, \mathcal{L}\left[ X_{ref} - X \right] | ||
|
|
||
| where :math:`\mathcal{L}` is a scale-selective filter that removes the | ||
| short wavelengths. Rather than performing this filtering with a global | ||
| spectral transform, :math:`\mathcal{L}` is applied as a convolution in | ||
| physical space. The motivation for this choice, and the derivation of the | ||
| convolution kernel on the sphere, are described in | ||
| :ref:`nudging_science_convolution`. | ||
|
|
||
| .. _nudging_science_weights: | ||
|
|
||
| Nudging weights | ||
| ---------------- | ||
|
|
||
| In both of the above methods, the increment is scaled by a single weight | ||
| :math:`w`, which combines a vertical tapering factor, a spin-up ramp, and a | ||
| relaxation-timescale factor: | ||
|
|
||
| .. math:: :label: eq:nudging_weight | ||
|
|
||
| w = w_{taper} \; r_{spinup} \; \min\left(1, \frac{\Delta t}{\tau}\right) | ||
|
|
||
| where: | ||
|
|
||
| * :math:`w_{taper}` is a height-dependent factor, computed as described in | ||
| :ref:`nudging_science_vertical_treatment`, that ramps the nudging on and | ||
| off over a chosen range of vertical levels; | ||
| * :math:`r_{spinup}` is a factor that ramps linearly from 0 to 1 over a | ||
| configured spin-up period, described below; | ||
| * :math:`\Delta t` is the model timestep and :math:`\tau` is a configured | ||
| relaxation timescale. If :math:`\tau` is set to zero, this factor is | ||
| instead set to 1, so that the field is relaxed fully towards the | ||
| reference state within a single timestep. | ||
|
|
||
| Spin-up ramp | ||
| ~~~~~~~~~~~~ | ||
|
|
||
| The nudging weight can be ramped up gradually over a configurable spin-up | ||
| period :math:`[t_{start}, t_{end}]`:, allowing forecasts over short time scales | ||
| to be unperturbed. | ||
|
|
||
| .. math:: :label: eq:nudging_spinup | ||
|
|
||
| r_{spinup} = | ||
| \begin{cases} | ||
| 0 & t \le t_{start} \\ | ||
| \dfrac{t - t_{start}}{t_{end} - t_{start}} & t_{start} < t < t_{end} \\ | ||
| 1 & t \ge t_{end} | ||
| \end{cases} | ||
|
|
||
| where :math:`t` is the elapsed model time since the start of the run. If | ||
| :math:`t_{start}` and :math:`t_{end}` are equal, the ramp is skipped and | ||
| :math:`r_{spinup} = 1` once :math:`t` exceeds this value. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| .. ----------------------------------------------------------------------------- | ||
| (c) Crown copyright Met Office. All rights reserved. | ||
| The file LICENCE, distributed with this code, contains details of the terms | ||
| under which the code may be used. | ||
| ----------------------------------------------------------------------------- | ||
| .. _nudging_science_index: | ||
|
|
||
| Nudging | ||
| ================ | ||
|
|
||
| Nudging is a technique for relaxing a free-running simulation towards an | ||
| external reference state. It can be targeted at a chosen | ||
| range of horizontal scales and a chosen range of vertical levels. This | ||
| allows the large-scale state of the simulation to be kept close to the | ||
| reference state, while still permitting the model to generate its own | ||
| small-scale variability. Two approaches are available for this nudging: | ||
| selecting only certain horizontal scales (known as spectral nudging), or | ||
| relaxing the model state directly towards the reference state at every | ||
| horizontal scale (known as Newtonian relaxation). | ||
|
|
||
| This section describes the scientific formulation of nudging in GungHo. It | ||
| begins with an overview of the method and the relaxation increment, before | ||
| describing how the large scales can be selected using a convolution, how this | ||
| may be computed efficiently on a coarse mesh, and finally how the reference | ||
| data is prepared in the vertical. For details of how to configure and | ||
| enable nudging, see the :ref:`nudging_user_index` section of the User | ||
| Guide. | ||
|
|
||
| .. toctree:: | ||
| :maxdepth: 1 | ||
|
|
||
| overview | ||
| formulation | ||
| convolution | ||
| multiresolution | ||
| vertical_treatment |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.