Limb Scatter Cloud Retrieval

Limb Scatter Cloud Retrieval#

Here we demonstrate the retrieval of cloud height, width, and optical depth. Similar to other examples we must provide information on the optical parameters.

import numpy as np
import sasktran2 as sk
import skretrieval as skr

In this example we use a Mie distribution with a fixed particle size to define our cloud optical properties.

@skr.Retrieval.register_optical_property("cloud")
def cloud_optical_prop(*args, **kwargs):
    refrac = sk.mie.refractive.H2SO4()
    dist = sk.mie.distribution.LogNormalDistribution().freeze(
        mode_width=1.6, median_radius=80.0,
    )

    db = sk.database.MieDatabase(
        dist,
        refrac,
        np.array([469.0, 750.0]),
    )

    return db

We configure the state vector for the three parameters (vertical_optical_depth, width_fwhm_m, height_m) required by the Gaussian extinction profile constituent.

# Measurement tangent altitudes
tan_alts = np.arange(10000, 45000, 1000)

# Triplets
triplets = {
    "745": {
        "wavelength": [745],
        "weights": [1],
        "altitude_range": [0, 40000],
        "normalization_range": [40000, 45000],
    },
}

# Get the wavelengths required for the triplets
wavel = np.unique(np.concatenate([triplets[t]["wavelength"] for t in triplets])).astype(float)

# Set up a simulated observation with our tangent altitudes, wavelengths, and use 1.5x the initial guess for ozone
obs = skr.observation.SimulatedLimbObservation(
    cos_sza=0.2,
    relative_azimuth=0,
    observer_altitude=200000,
    reference_latitude=20,
    reference_longitude=20,
    tangent_altitudes=tan_alts,
    sample_wavelengths=wavel,
    state_adjustment_factors={
        "cloud": {
            "vertical_optical_depth": 1.5,
            "width_fwhm_m": 1.5,
            "height_m": 1.5,
        }
    },
)

# Construct our measurement vectors
meas_vec = {}
for name, t in triplets.items():
    meas_vec[name] = skr.measvec.Triplet(
        t["wavelength"], t["weights"], t["altitude_range"], t["normalization_range"], normalize=False
    )

# Set up the retrieval object
ret = skr.Retrieval(
    obs,
    measvec=meas_vec,
    minimizer="rodgers",
    target_kwargs={"rescale_state_space": True},
    state_kwargs={
        "altitude_grid": np.arange(0, 70000, 1000),
        "aerosols": {
            "cloud": {
                "type": "gaussian_extinction_profile",
                "nominal_wavelength": 745,
                "retrieved_quantities": {
                    "vertical_optical_depth": {
                        "prior_influence": 1e0,
                        "tikh_factor": 1e-2,
                        "min_value": 1e-9,
                        "max_value": 10
                    },
                    "width_fwhm_m": {
                        "prior_influence": 1e0,
                        "tikh_factor": 1e-2,
                        "min_value": 1e-9,
                        "max_value": 20000
                    },
                    "height_m": {
                        "prior_influence": 1e0,
                        "tikh_factor": 1e-2,
                        "min_value": 0,
                        "max_value": 25000
                    },
                },
                "prior": {
                    "vertical_optical_depth": {"type": "constant", "value": 0.05},
                    "width_fwhm_m": {"type": "constant", "value": 5000},
                    "height_m": {"type": "constant", "value": 15000},
                }
            },
        },
    },
)

# Do the retrieval
results = ret.retrieve()

# Display the results
print(results["state"])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[3], line 85
     81     },
     82 )
     83 
     84 # Do the retrieval
---> 85 results = ret.retrieve()
     86 
     87 # Display the results
     88 print(results["state"])

File ~/checkouts/readthedocs.org/user_builds/skretrieval/checkouts/stable/src/skretrieval/retrieval/processing.py:402, in Retrieval.retrieve(self, enabled_state_elements, enabled_measurement_vectors)
    399 results["meas_l1"] = meas_l1
    400 results["simulated_l1"] = final_l1
--> 402 results["state"] = self._state_vector.describe(min_results)
    404 return self._construct_output(results)

File ~/checkouts/readthedocs.org/user_builds/skretrieval/checkouts/stable/src/skretrieval/retrieval/statevector/altitude.py:109, in AltitudeNativeStateVector.describe(self, rodgers_output)
     97 def describe(self, rodgers_output: dict) -> xr.Dataset:
     98     """
     99     Returns a human readable dataset containing the state vector elements
    100 
   (...)    107     xr.Dataset
    108     """
--> 109     result = super().describe(rodgers_output)
    111     result.coords["altitude"] = self._altitude_grid
    113     return result

File ~/checkouts/readthedocs.org/user_builds/skretrieval/checkouts/stable/src/skretrieval/retrieval/statevector/__init__.py:129, in StateVector.describe(self, rodgers_output, **kwargs)
    126 end = start + len(state_element.state())
    128 s = slice(start, end)
--> 129 ds = state_element.describe(
    130     covariance=covar[s, s],
    131     averaging_kernel=averaging_kernel[s, s],
    132     **kwargs,
    133 )
    134 if ds is not None:
    135     all_ds.append(ds)

File ~/checkouts/readthedocs.org/user_builds/skretrieval/checkouts/stable/src/skretrieval/retrieval/statevector/constituent.py:254, in StateVectorElementConstituent.describe(self, **kwargs)
    249 ds[self._constituent_name + "_" + property_name + "_prior"] = (
    250     xr.DataArray(prior_values, dims=["altitude"])
    251 )
    252 if end - start == 1:  # scalar property
    253     ds[self._constituent_name + "_" + property_name] = xr.DataArray(
--> 254         float(getattr(self._constituent, property_name))
    255     )
    257     ds[self._constituent_name + "_" + property_name + "_prior"] = float(
    258         self._prior[property_name].state
    259     )
    261     if "covariance" in kwargs:

TypeError: only 0-dimensional arrays can be converted to Python scalars