Open RobertPincus opened 4 months ago
We discussed this at a group meeting recently.
Conceptually we can think of each problem as having optical properties, sources (of radiation), and boundary conditions. The combination of optical properties and sources defines the kind of problem to be solved; it's also what comes back from the gas optics. Users will specify boundary conditions.
We could distinguish these, e.g.
gas_optics = rrtmgp.GasOptics(SCHEME_DATA)
atmosphere = xr.open_dataset(SOME_FILE) # temperature, pressure, gas concentrations
optical_props, sources = gas_optics.gas_optics(atmosphere)
bcs = atmosphere # with agreed names for surface properties, say
flux_up, flux_dn = rte.solve(optical_props, sources, bcs)
This makes everything clear. One clear disadvantage is that the optical_props, sources, and boundary conditions share coordinates in space and along the spectrum. To me that suggests putting them in the same dataset:
gas_optics = rrtmgp.GasOptics(SCHEME_DATA)
atmosphere = xr.open_dataset(SOME_FILE) # temperature, pressure, gas concentrations
problem = gas_optics.gas_optics(atmosphere)
problem["surface_emissivity"] = 1.
flux_up, flux_dn = rte.solve(problem)
This is conceptually less clear and relies (more?) on conventions for arrays within datasets.
@tcmetzger these are some nice "spelling" examples for us to implement
@tcmetzger @sehnem One thought after discussions with @brendancol earlier today: optical properties and source functions both have a spectral dimension/discretization. In general, there are spectral "bands" that cover particular frequencies/wavelengths (and have starting and ending values of those coordinates); for the gas optics there may also be "g-points" within each band that aren't ordered in any particular way.
This comes up when creating a problem definition/set of optical properties from multiple components in the atmosphere (like gases and clouds) - not only do we have to ensure that the discretizations are the same but we need the ability to broadcasts values defined on bands to each g-point within the band. Like this, if we use a single dataset for the whole problem:
gas_optics = rrtmgp.GasOptics(SCHEME_DATA)
cloud_optics = rrtmgp.CloudOptics(MORE_SCHEME_DATA)
atmosphere = xr.open_dataset(SOME_FILE) # temperature, pressure, gas concentrations
clouds = xr.open_dataset(SOME_OTHER_FILE) # cloud properties
problem = gas_optics.gas_optics(atmosphere)
# "problem" is defined on g-points
cloud_optics(clouds).add_to(problem) # or maybe problem += cloud_optics(clouds)
#cloud_optics(clouds) is defined on bands
problem["surface_emissivity"] = 1.
flux_up, flux_dn = rte.solve(problem)
In thinking about a user-friendly Python front end we think about how well the Fortran design would work.
Specifying problems
Radiation problems are defined in one of three ways - three sets of "optical properties". Using the Fortran notation:
1scl
problems are defined in terms oftau
2str
problems are defined in terms oftau
,ssa
,g
nstr
problems are defined in terms oftau
,ssa
,p
(we don't currently have much implemented in Fortran)Each variable might depend on a vertical coordinate (
ilay
) and/or a spectral coordinate (igpt
);p
also has a "moment" dimension (imom
). The underlying kernels all operate on more than one profile at a time (icol
) as the first dimension.Planets receive radiation from their host star and emit radiation themselves. For the purposes of gas optics we treat these as distinct, so we have two gas optics variants:
_int
for internal sources represent planetary radiation and returns layer, level, and surface sources. Each has a spectral dimension; there is one more level than layer, and the surface has no vertical extent._ext
represents stellar radiation. It returns the solar source (inc_flux
) which has a single spectral dimension.Gas optics calculations also return the set of
1scl
,2str
, ornstr
optical properties depending on user desires.Solving problems
The solvers depend on whether the sources are internal (
lw
for longwave) or external (sw
for shortwave). Each takes a set of optical properties (e.g.noscat
solvers use1scl
optical properties) and the corresponding set (int/ext) of source functions.In practice shortwave problems always use a two-stream specification, while longwave solvers might use either a scalar or a two-stream specification.
Encapsulation
In the Fortran interface there is one class grouping together the optical properties and a second grouping together the longwave source functions; the shortwave source is passed around as a plain array. Using classes makes for a smaller number of variables and ensures the right grouping.
Does this approach make sense in Python too?