Using data from GEOS-FP

This example demonstrates how to use the GEOS-FP data loader in the EarthSciML ecosystem. The GEOS-FP data loader is used to load data from the GEOS-FP dataset.

First, let's initialize some packages and set up the GEOS-FP equation system.

using EarthSciData, EarthSciMLBase
using DomainSets, ModelingToolkit, MethodOfLines, DifferentialEquations
using ModelingToolkit: t, D
using Dates, Plots, DataFrames
using DynamicQuantities
using DynamicQuantities: dimension

# Set up system
@parameters(
    lev,
    lon, [unit=u"rad"],
    lat, [unit=u"rad"],
)
geosfp, geosfp_updater = GEOSFP("4x5")

geosfp

\[ \begin{align} A3dyn_{+}DTRAIN\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( DTRAIN \right), t, lon, lat, lev \right) \\ A3dyn_{+}OMEGA\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( OMEGA \right), t, lon, lat, lev \right) \\ A3dyn_{+}RH\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( RH \right), t, lon, lat, lev \right) \\ A3dyn_{+}U\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( U \right), t, lon, lat, lev \right) \\ A3dyn_{+}V\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( V \right), t, lon, lat, lev \right) \\ A3cld_{+}CLOUD\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( CLOUD \right), t, lon, lat, lev \right) \\ A3cld_{+}OPTDEPTH\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( OPTDEPTH \right), t, lon, lat, lev \right) \\ A3cld_{+}QCCU\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( QCCU \right), t, lon, lat, lev \right) \\ A3cld_{+}QI\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( QI \right), t, lon, lat, lev \right) \\ A3cld_{+}QL\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( QL \right), t, lon, lat, lev \right) \\ A3cld_{+}TAUCLI\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( TAUCLI \right), t, lon, lat, lev \right) \\ A3cld_{+}TAUCLW\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( TAUCLW \right), t, lon, lat, lev \right) \\ I3_{+}PS\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PS \right), t, lon, lat \right) \\ I3_{+}PV\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PV \right), t, lon, lat, lev \right) \\ I3_{+}QV\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( QV \right), t, lon, lat, lev \right) \\ I3_{+}T\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( T \right), t, lon, lat, lev \right) \\ A3mstE_{+}CMFMC\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( CMFMC \right), t, lon, lat, lev \right) \\ A3mstE_{+}PFICU\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PFICU \right), t, lon, lat, lev \right) \\ A3mstE_{+}PFILSAN\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PFILSAN \right), t, lon, lat, lev \right) \\ A3mstE_{+}PFLCU\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PFLCU \right), t, lon, lat, lev \right) \\ A3mstE_{+}PFLLSAN\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PFLLSAN \right), t, lon, lat, lev \right) \\ A1_{+}ALBEDO\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( ALBEDO \right), t, lon, lat \right) \\ A1_{+}CLDTOT\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( CLDTOT \right), t, lon, lat \right) \\ A1_{+}EFLUX\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( EFLUX \right), t, lon, lat \right) \\ A1_{+}EVAP\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( EVAP \right), t, lon, lat \right) \\ A1_{+}FRSEAICE\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( FRSEAICE \right), t, lon, lat \right) \\ A1_{+}FRSNO\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( FRSNO \right), t, lon, lat \right) \\ A1_{+}GRN\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( GRN \right), t, lon, lat \right) \\ A1_{+}GWETROOT\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( GWETROOT \right), t, lon, lat \right) \\ A1_{+}GWETTOP\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( GWETTOP \right), t, lon, lat \right) \\ A1_{+}HFLUX\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( HFLUX \right), t, lon, lat \right) \\ A1_{+}LAI\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( LAI \right), t, lon, lat \right) \\ A1_{+}LWI\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( LWI \right), t, lon, lat \right) \\ A1_{+}LWGNT\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( LWGNT \right), t, lon, lat \right) \\ A1_{+}LWTUP\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( LWTUP \right), t, lon, lat \right) \\ A1_{+}PARDF\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PARDF \right), t, lon, lat \right) \\ A1_{+}PARDR\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PARDR \right), t, lon, lat \right) \\ A1_{+}PBLH\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PBLH \right), t, lon, lat \right) \\ A1_{+}PRECANV\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PRECANV \right), t, lon, lat \right) \\ A1_{+}PRECCON\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PRECCON \right), t, lon, lat \right) \\ A1_{+}PRECLSC\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PRECLSC \right), t, lon, lat \right) \\ A1_{+}PRECSNO\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PRECSNO \right), t, lon, lat \right) \\ A1_{+}PRECTOT\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PRECTOT \right), t, lon, lat \right) \\ A1_{+}QV2M\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( QV2M \right), t, lon, lat \right) \\ A1_{+}SEAICE00\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE00 \right), t, lon, lat \right) \\ A1_{+}SEAICE10\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE10 \right), t, lon, lat \right) \\ A1_{+}SEAICE20\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE20 \right), t, lon, lat \right) \\ A1_{+}SEAICE30\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE30 \right), t, lon, lat \right) \\ A1_{+}SEAICE40\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE40 \right), t, lon, lat \right) \\ A1_{+}SEAICE50\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE50 \right), t, lon, lat \right) \\ A1_{+}SEAICE60\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE60 \right), t, lon, lat \right) \\ A1_{+}SEAICE70\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE70 \right), t, lon, lat \right) \\ A1_{+}SEAICE80\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE80 \right), t, lon, lat \right) \\ A1_{+}SEAICE90\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE90 \right), t, lon, lat \right) \\ A1_{+}SLP\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SLP \right), t, lon, lat \right) \\ A1_{+}SNODP\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SNODP \right), t, lon, lat \right) \\ A1_{+}SNOMAS\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SNOMAS \right), t, lon, lat \right) \\ A1_{+}SWGDN\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SWGDN \right), t, lon, lat \right) \\ A1_{+}TO3\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( TO3 \right), t, lon, lat \right) \\ A1_{+}TROPPT\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( TROPPT \right), t, lon, lat \right) \\ A1_{+}TS\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( TS \right), t, lon, lat \right) \\ A1_{+}T2M\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( T2M \right), t, lon, lat \right) \\ A1_{+}U10M\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( U10M \right), t, lon, lat \right) \\ A1_{+}USTAR\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( USTAR \right), t, lon, lat \right) \\ A1_{+}V10M\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( V10M \right), t, lon, lat \right) \\ A1_{+}Z0M\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( Z0M \right), t, lon, lat \right) \\ A1_{+}T10M\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( T10M \right), t, lon, lat \right) \\ A1_{+}Q850\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( Q850 \right), t, lon, lat \right) \\ A3mstC_{+}DQRCU\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( DQRCU \right), t, lon, lat, lev \right) \\ A3mstC_{+}DQRLSAN\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( DQRLSAN \right), t, lon, lat, lev \right) \\ A3mstC_{+}REEVAPCN\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( REEVAPCN \right), t, lon, lat, lev \right) \\ A3mstC_{+}REEVAPLS\left( t \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( REEVAPLS \right), t, lon, lat, lev \right) \\ P\left( t \right) &= P_{unit} \mathrm{DataInterpolations.LinearInterpolation{Vector{Float64}, UnitRange{Int64}, Vector{Float64}, Vector{Float64}, Float64}([0.0, 4.804826, 659.3752000000001, 1313.48, 1961.311, 2609.201, 3257.081, 3898.201, 4533.901, 5169.611, 5805.321, 6436.264, 7062.197999999999, 7883.4220000000005, 8909.992, 9936.521, 10918.17, 11895.86, 12869.59, 14291.0, 15626.0, 16960.9, 18161.9, 19309.7, 20325.899999999998, 21215.0, 21877.600000000002, 22389.8, 22436.3, 21686.5, 20119.2, 17693.0, 15039.3, 12783.7, 10866.3, 9236.572, 7851.231, 6660.340999999999, 5638.791, 4764.391, 4017.541, 3381.0009999999997, 2836.781, 2373.0409999999997, 1979.1599999999999, 1645.71, 1364.34, 1127.69, 929.2942, 761.9842, 621.6801, 504.68010000000004, 407.6571, 327.6431, 262.0211, 208.497, 165.079, 130.05100000000002, 101.94399999999999, 79.51341, 61.677910000000004, 47.58061, 36.50411, 27.85261, 21.134900000000002, 15.9495, 11.9703, 8.934502, 6.600001, 4.758501, 3.27, 2.0, 1.0], 1:73, Float64[], DataInterpolations.LinearParameterCache{Vector{Float64}}(Float64[]), false, FindFirstFunctions.Guesser{UnitRange{Int64}}(1:73, Base.RefValue{Int64}(1), true), false, true)}\left( lev \right) + \mathrm{DataInterpolations.LinearInterpolation{Vector{Float64}, UnitRange{Int64}, Vector{Float64}, Vector{Float64}, Float64}([1.0, 0.984952, 0.963406, 0.941865, 0.920387, 0.898908, 0.877429, 0.856018, 0.8346609, 0.8133039, 0.7919469, 0.7706375, 0.7493782, 0.721166, 0.6858999, 0.6506349, 0.6158184, 0.5810415, 0.5463042, 0.4945902, 0.4437402, 0.3928911, 0.3433811, 0.2944031, 0.2467411, 0.2003501, 0.1562241, 0.1136021, 0.06372006, 0.02801004, 0.006960025, 8.175413e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 1:73, Float64[], DataInterpolations.LinearParameterCache{Vector{Float64}}(Float64[]), false, FindFirstFunctions.Guesser{UnitRange{Int64}}(1:73, Base.RefValue{Int64}(1), true), false, true)}\left( lev \right) I3_{+}PS\left( t \right) \end{align} \]

Note that the GEOSFP function returns to things, an equation system and an object that can used to update the time in the underlying data loaders. We can see above the different variables that are available in the GEOS-FP dataset. But also, here they are in table form:

vars = unknowns(geosfp)
DataFrame(
        :Name => [string(Symbolics.tosymbol(v, escape=false)) for v ∈ vars],
        :Units => [dimension(ModelingToolkit.get_unit(v)) for v ∈ vars],
        :Description => [ModelingToolkit.getdescription(v) for v ∈ vars],
)
73×3 DataFrame
RowNameUnitsDescription
StringDimensio…String
1A3dyn₊DTRAINm⁻² kg s⁻²Detrainment cloud mass flux
2A3dyn₊OMEGAm⁻¹ kg s⁻³Vertical pressure velocity
3A3dyn₊RHRelative humidity
4A3dyn₊Um s⁻¹Eastward component of wind
5A3dyn₊Vm s⁻¹Northward component of wind
6A3cld₊CLOUDTotal cloud fraction in grid box
7A3cld₊OPTDEPTHTotal in-cloud optical thickness (visible band)
8A3cld₊QCCUCloud condensate mixing ratio, convective updraft
9A3cld₊QICloud ice water mixing ratio
10A3cld₊QLCloud liquid water mixing ratio
11A3cld₊TAUCLIIn-cloud ice optical thickness (visible band)
12A3cld₊TAUCLWIn-cloud water optical thickness (visible band)
13I3₊PSm⁻¹ kg s⁻²Pressure at the surface
14I3₊PVm⁻² kg⁻¹ s⁻¹ KErtel potential vorticity
15I3₊QVSpecific humidity
16I3₊TKTemperature
17A3mstE₊CMFMCm⁻² kg s⁻²Upward moist convective mass flux
18A3mstE₊PFICUm⁻² kg s⁻¹Downward flux of ice precipitation (convective)
19A3mstE₊PFILSANm⁻² kg s⁻¹Downward flux of ice precipitation (large scale + anvil)
20A3mstE₊PFLCUm⁻² kg s⁻¹Downward flux of liquid precipitation (convective)
21A3mstE₊PFLLSANm⁻² kg s⁻¹Downward flux of liquid precipitation (large scale + anvil)
22A1₊ALBEDOSurface albedo
23A1₊CLDTOTTotal cloud fraction
24A1₊EFLUXkg s⁻³Latent heat flux (positive upward)
25A1₊EVAPm⁻² kg s⁻²Surface evaporation
26A1₊FRSEAICEFraction of sea ice on surface
27A1₊FRSNOFractional snow-covered area
28A1₊GRNVegetation greenness fraction
29A1₊GWETROOTRoot zone soil wetness
30A1₊GWETTOPTop soil wetness
31A1₊HFLUXkg s⁻³Sensible heat flux (positive upward)
32A1₊LAILeaf area index
33A1₊LWILand/water/ice flags
34A1₊LWGNTkg s⁻³Net longwave flux at the ground
35A1₊LWTUPkg s⁻³Upward longwave flux at top of atmosphere (TOA)
36A1₊PARDFkg s⁻³Surface downward PAR diffuse flux
37A1₊PARDRkg s⁻³Surface downward PAR beam flux
38A1₊PBLHmPlanetary boundary layer height above surface
39A1₊PRECANVm⁻² kg s⁻¹Surface precipitation flux from anvils
40A1₊PRECCONm⁻² kg s⁻¹Surface precipitation flux from convection
41A1₊PRECLSCm⁻² kg s⁻¹Surface precipitation flux from large-scale
42A1₊PRECSNOm⁻² kg s⁻¹Surface precipitation flux from snow
43A1₊PRECTOTm⁻² kg s⁻¹Total surface precipitation flux
44A1₊QV2MSpecific humidity at 2m above the displacement height
45A1₊SEAICE00Fraction of grid box that has 0-10% sea ice coverage
46A1₊SEAICE10Fraction of grid box that has 10-20% sea ice coverage
47A1₊SEAICE20Fraction of grid box that has 20-30% sea ice coverage
48A1₊SEAICE30Fraction of grid box that has 30-40% sea ice coverage
49A1₊SEAICE40Fraction of grid box that has 40-50% sea ice coverage
50A1₊SEAICE50Fraction of grid box that has 50-60% sea ice coverage
51A1₊SEAICE60Fraction of grid box that has 60-70% sea ice coverage
52A1₊SEAICE70Fraction of grid box that has 70-80% sea ice coverage
53A1₊SEAICE80Fraction of grid box that has 80-90% sea ice coverage
54A1₊SEAICE90Fraction of grid box that has 90-100% sea ice coverage
55A1₊SLPm⁻¹ kg s⁻²Sea level pressure
56A1₊SNODPmSnow depth
57A1₊SNOMASm⁻² kgSnow mass
58A1₊SWGDNkg s⁻³Surface incident shortwave flux
59A1₊TO3m⁻² molTotal column ozone
60A1₊TROPPTm⁻¹ kg s⁻²Temperature-based tropopause pressure
61A1₊TSKSurface skin temperature
62A1₊T2MKTemperature 2m above displacement height
63A1₊U10Mm s⁻¹Eastward wind 10m above displacement height
64A1₊USTARm s⁻¹Friction velocity
65A1₊V10Mm s⁻¹Northward wind 10m above displacement height
66A1₊Z0MmRoughness length, momentum
67A1₊T10MKTemperature at 10 m above the displacement height
68A1₊Q850Specific humidity at 850 hPa
69A3mstC₊DQRCUs⁻¹Precipitation production rate -- convective
70A3mstC₊DQRLSANs⁻¹Precipitation production rate -- large scale + anvil
71A3mstC₊REEVAPCNs⁻¹Evaporation of precipitating convective condensate
72A3mstC₊REEVAPLSEvaporation of precipitating large-scale & anvil condensate
73Pm⁻¹ kg s⁻²Pressure

The GEOS-FP equation system isn't an ordinary differential equation (ODE) system, so we can't run it by itself. To fix this, we create another equation system that is an ODE. (We don't actually end up using this system for anything, it's just necessary to get the system to compile.)

function Example()
    @variables c(t) = 5.0 [unit=u"s"]
    ODESystem([D(c) ~ sin(lat * 6) + sin(lon * 6)], t, name=:Docs₊Example)
end
examplesys = Example()

\[ \begin{align} \frac{\mathrm{d} c\left( t \right)}{\mathrm{d}t} &= \sin\left( 6 lon \right) + \sin\left( 6 lat \right) \end{align} \]

Now, let's couple these two systems together, and also add in advection and some information about the domain:

domain = DomainInfo(
    partialderivatives_δxyδlonlat,
    constIC(0.0, t ∈ Interval(Dates.datetime2unix(DateTime(2022, 1, 1)), Dates.datetime2unix(DateTime(2022, 1, 3)))),
    zerogradBC(lat ∈ Interval(deg2rad(-80.0f0), deg2rad(80.0f0))),
    periodicBC(lon ∈ Interval(deg2rad(-180.0f0), deg2rad(180.0f0))),
    zerogradBC(lev ∈ Interval(1.0f0, 11.0f0)),
)

composed_sys = couple(examplesys, domain, geosfp, geosfp_updater)
pde_sys = convert(PDESystem, composed_sys)

\[ \begin{align} \frac{\mathrm{d}}{\mathrm{d}t} Docs_{+}Example_{+}c\left( t, lat, lon, lev \right) &= \sin\left( 6 lon \right) + \sin\left( 6 lat \right) \\ GEOSFP_{+}A3dyn_{+}DTRAIN\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( DTRAIN \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3dyn_{+}OMEGA\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( OMEGA \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3dyn_{+}RH\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( RH \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3dyn_{+}U\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( U \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3dyn_{+}V\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( V \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3cld_{+}CLOUD\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( CLOUD \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3cld_{+}OPTDEPTH\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( OPTDEPTH \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3cld_{+}QCCU\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( QCCU \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3cld_{+}QI\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( QI \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3cld_{+}QL\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( QL \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3cld_{+}TAUCLI\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( TAUCLI \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3cld_{+}TAUCLW\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( TAUCLW \right), t, lon, lat, lev \right) \\ GEOSFP_{+}I3_{+}PS\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PS \right), t, lon, lat \right) \\ GEOSFP_{+}I3_{+}PV\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PV \right), t, lon, lat, lev \right) \\ GEOSFP_{+}I3_{+}QV\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( QV \right), t, lon, lat, lev \right) \\ GEOSFP_{+}I3_{+}T\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( T \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3mstE_{+}CMFMC\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( CMFMC \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3mstE_{+}PFICU\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PFICU \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3mstE_{+}PFILSAN\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PFILSAN \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3mstE_{+}PFLCU\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PFLCU \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3mstE_{+}PFLLSAN\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PFLLSAN \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A1_{+}ALBEDO\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( ALBEDO \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}CLDTOT\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( CLDTOT \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}EFLUX\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( EFLUX \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}EVAP\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( EVAP \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}FRSEAICE\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( FRSEAICE \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}FRSNO\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( FRSNO \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}GRN\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( GRN \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}GWETROOT\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( GWETROOT \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}GWETTOP\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( GWETTOP \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}HFLUX\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( HFLUX \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}LAI\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( LAI \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}LWI\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( LWI \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}LWGNT\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( LWGNT \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}LWTUP\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( LWTUP \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}PARDF\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PARDF \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}PARDR\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PARDR \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}PBLH\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PBLH \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}PRECANV\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PRECANV \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}PRECCON\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PRECCON \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}PRECLSC\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PRECLSC \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}PRECSNO\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PRECSNO \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}PRECTOT\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( PRECTOT \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}QV2M\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( QV2M \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}SEAICE00\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE00 \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}SEAICE10\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE10 \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}SEAICE20\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE20 \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}SEAICE30\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE30 \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}SEAICE40\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE40 \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}SEAICE50\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE50 \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}SEAICE60\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE60 \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}SEAICE70\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE70 \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}SEAICE80\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE80 \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}SEAICE90\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SEAICE90 \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}SLP\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SLP \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}SNODP\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SNODP \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}SNOMAS\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SNOMAS \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}SWGDN\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( SWGDN \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}TO3\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( TO3 \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}TROPPT\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( TROPPT \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}TS\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( TS \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}T2M\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( T2M \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}U10M\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( U10M \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}USTAR\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( USTAR \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}V10M\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( V10M \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}Z0M\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( Z0M \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}T10M\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( T10M \right), t, lon, lat \right) \\ GEOSFP_{+}A1_{+}Q850\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( Q850 \right), t, lon, lat \right) \\ GEOSFP_{+}A3mstC_{+}DQRCU\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( DQRCU \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3mstC_{+}DQRLSAN\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( DQRLSAN \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3mstC_{+}REEVAPCN\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( REEVAPCN \right), t, lon, lat, lev \right) \\ GEOSFP_{+}A3mstC_{+}REEVAPLS\left( t, lat, lon, lev \right) &= \mathrm{interp}_{unsafe}\left( \mathrm{GEOSFPFileSet}\left( REEVAPLS \right), t, lon, lat, lev \right) \\ GEOSFP_{+}P\left( t, lat, lon, lev \right) &= GEOSFP_{+}P_{unit} \mathrm{DataInterpolations.LinearInterpolation{Vector{Float64}, UnitRange{Int64}, Vector{Float64}, Vector{Float64}, Float64}([0.0, 4.804826, 659.3752000000001, 1313.48, 1961.311, 2609.201, 3257.081, 3898.201, 4533.901, 5169.611, 5805.321, 6436.264, 7062.197999999999, 7883.4220000000005, 8909.992, 9936.521, 10918.17, 11895.86, 12869.59, 14291.0, 15626.0, 16960.9, 18161.9, 19309.7, 20325.899999999998, 21215.0, 21877.600000000002, 22389.8, 22436.3, 21686.5, 20119.2, 17693.0, 15039.3, 12783.7, 10866.3, 9236.572, 7851.231, 6660.340999999999, 5638.791, 4764.391, 4017.541, 3381.0009999999997, 2836.781, 2373.0409999999997, 1979.1599999999999, 1645.71, 1364.34, 1127.69, 929.2942, 761.9842, 621.6801, 504.68010000000004, 407.6571, 327.6431, 262.0211, 208.497, 165.079, 130.05100000000002, 101.94399999999999, 79.51341, 61.677910000000004, 47.58061, 36.50411, 27.85261, 21.134900000000002, 15.9495, 11.9703, 8.934502, 6.600001, 4.758501, 3.27, 2.0, 1.0], 1:73, Float64[], DataInterpolations.LinearParameterCache{Vector{Float64}}(Float64[]), false, FindFirstFunctions.Guesser{UnitRange{Int64}}(1:73, Base.RefValue{Int64}(1), true), false, true)}\left( lev \right) + \mathrm{DataInterpolations.LinearInterpolation{Vector{Float64}, UnitRange{Int64}, Vector{Float64}, Vector{Float64}, Float64}([1.0, 0.984952, 0.963406, 0.941865, 0.920387, 0.898908, 0.877429, 0.856018, 0.8346609, 0.8133039, 0.7919469, 0.7706375, 0.7493782, 0.721166, 0.6858999, 0.6506349, 0.6158184, 0.5810415, 0.5463042, 0.4945902, 0.4437402, 0.3928911, 0.3433811, 0.2944031, 0.2467411, 0.2003501, 0.1562241, 0.1136021, 0.06372006, 0.02801004, 0.006960025, 8.175413e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 1:73, Float64[], DataInterpolations.LinearParameterCache{Vector{Float64}}(Float64[]), false, FindFirstFunctions.Guesser{UnitRange{Int64}}(1:73, Base.RefValue{Int64}(1), true), false, true)}\left( lev \right) GEOSFP_{+}I3_{+}PS\left( t, lat, lon, lev \right) \end{align} \]

You can see above that we add both geosfp and geosfp_updater to our coupled system. If we didn't include the updater, the resulting model would not give the correct results.

Now, finally, we can run the simulation and plot the GEOS-FP wind fields in the result:

(The code below is commented out because it is very slow right now. A faster solution is coming soon!)

# discretization = MOLFiniteDifference([lat => 10, lon => 10, lev => 10], t, approx_order=2)
# @time pdeprob = discretize(pde_sys, discretization)

# pdesol = solve(pdeprob, Tsit5(), saveat=3600.0)

# discrete_lon = pdesol[lon]
# discrete_lat = pdesol[lat]
# discrete_lev = pdesol[lev]
# discrete_t = pdesol[t]

# @variables meanwind₊u(..) meanwind₊v(..) examplesys₊c(..)
# sol_u = pdesol[meanwind₊u(t, lat, lon, lev)]
# sol_v = pdesol[meanwind₊v(t, lat, lon, lev)]
# sol_c = pdesol[examplesys₊c(t, lat, lon, lev)]

# anim = @animate for k in 1:length(discrete_t)
#     p1 = heatmap(discrete_lon, discrete_lat, sol_c[k, 1:end, 1:end, 2], clim=(minimum(sol_c[:, :, :, 2]), maximum(sol_c[:, :, :, 2])),
#             xlabel="Longitude", ylabel="Latitude", title="examplesys.c: $(Dates.unix2datetime(discrete_t[k]))")
#     p2 = heatmap(discrete_lon, discrete_lat, sol_u[k, 1:end, 1:end, 2], clim=(minimum(sol_u[:, :, :, 2]), maximum(sol_u[:, :, :, 2])), 
#             title="U")
#     p3 = heatmap(discrete_lon, discrete_lat, sol_v[k, 1:end, 1:end, 2], clim=(minimum(sol_v[:, :, :, 2]), maximum(sol_v[:, :, :, 2])),
#             title="V")
#     plot(p1, p2, p3, size=(800, 500))
# end
# gif(anim, "animation.gif", fps = 8)