FEISTY test cases#

The testcase module provides some utilites to generate domain and forcing data for a handful of feisty test cases.

Here we illustrate some of these utilties.

%load_ext autoreload
%autoreload 2
import matplotlib.pyplot as plt
import numpy as np
import xarray as xr

import feisty
/home/runner/work/feisty/feisty/feisty/__init__.py:2: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.
  from pkg_resources import DistributionNotFound, get_distribution

Idealized bathymetry#

domain_dict = feisty.testcase.domain_tanh_shelf(nx=22)
domain_dict
{'bathymetry': <xarray.DataArray 'bathymetry' (X: 22)> Size: 176B
 array([  30.04108171,   30.19902725,   31.17873201,   36.8321355 ,
          61.34734988,  131.85502453,  264.42098685,  437.55383604,
         609.22301965,  749.85055796,  851.52743149,  919.48569869,
         962.76570279,  989.53462509, 1005.8032774 , 1015.58739719,
        1021.43508524, 1024.91716307, 1026.98605941, 1028.21370613,
        1028.94160815, 1029.37300191])
 Coordinates:
   * X        (X) float64 176B -0.5 -0.2381 0.02381 0.2857 ... 4.476 4.738 5.0
 Attributes:
     long_name:  depth
     units:      m,
 'NX': 22}
domain_dict["bathymetry"].plot(marker="o")
plt.gca().invert_yaxis()
plt.title("Bathymetry")
Text(0.5, 1.0, 'Bathymetry')
_images/da7318e61b3369e6e377843dbc26a99d7565a153064d90a52143091651460ed9.png

Idealized forcing data#

The testcase subpackage of feisty includes a utilty to generate idealized forcing representing an annual cycle using harmonic function.

Here is an example dataset returned:

forcing = feisty.testcase.forcing_cyclic(domain_dict)
forcing.info()
xarray.Dataset {
dimensions:
	forcing_time = 365 ;
	X = 22 ;
	zooplankton = 1 ;

variables:
	object forcing_time(forcing_time) ;
	float64 X(X) ;
	float64 T_pelagic(forcing_time, X) ;
		T_pelagic:long_name = T_pelagic ;
		T_pelagic:units = degC ;
	float64 T_bottom(forcing_time, X) ;
		T_bottom:long_name = T_bottom ;
		T_bottom:units = degC ;
	float64 poc_flux_bottom(forcing_time, X) ;
		poc_flux_bottom:long_name = POC flux ;
		poc_flux_bottom:units = g/m^2/d ;
		poc_flux_bottom:b = 0.7 ;
	<U3 zooplankton(zooplankton) ;
	float64 zooC(zooplankton, forcing_time, X) ;
		zooC:long_name = Zooplankton biomass ;
		zooC:units = g/m^2 ;
		zooC:harmonic_parms = Zoo = {'mu': 4.0, 'amp_fraction': 0.2, 'phase': 10.0} ;
	float64 zoo_mort(zooplankton, forcing_time, X) ;
		zoo_mort:long_name = Zooplankton quadratic mortality ;
		zoo_mort:units = g/m^2/d ;

// global attributes:
	:note = Idealized cyclic forcing for FEISTY model. ;
}

Visualizing forcing data#

The temperature field looks like this:

fig, axs = plt.subplots(nrows=2)
forcing.T_pelagic.plot(ax=axs[0])
forcing.T_bottom.plot(ax=axs[1])
<matplotlib.collections.QuadMesh at 0x7fe605647990>
_images/3f68adbb4e26dc4faadcb786225515e426839bd2ba56a235ba7cc4468b602677.png

Or at a single X point:

forcing.T_pelagic.isel(X=0).plot(label="T_pelagic")
forcing.T_bottom.isel(X=0).plot(label="T_bottom")
plt.legend()
<matplotlib.legend.Legend at 0x7fe605728cd0>
_images/0e1d20cfda14b21ed61285ae13ca2f6884ee652171b786ddff32cd912c8c4542.png

Zooplankton and POC flux

zoo = forcing.zooC
for i in range(zoo.zooplankton.shape[0]):
    plt.figure()
    zoo.isel(X=0, zooplankton=i).plot()
_images/eabb7bd707ac51e71f78b07a3f28b5e0632d990982d4236e0c6f5840c526609c.png

Zooplankton mortality

zoo = forcing.zoo_mort
for i in range(zoo.zooplankton.shape[0]):
    plt.figure()
    zoo.isel(X=0, zooplankton=i).plot()
_images/7263007d45033462d31ada26c683b69ae459965f8095aa40b62329f3578cd3a5.png

POC flux

forcing.poc_flux_bottom.isel(X=0).plot()
[<matplotlib.lines.Line2D at 0x7fe5fd578350>]
_images/f8d26555ee89cf818c3038c1714f2462d1a9186e46e2775fb6fd73684cfff2bc.png