Пример #1
0
def compute_change(
    before: Checkpoint,
    after: Checkpoint,
    tendency_variables: Set[str],
    storage_variables: Set[str],
    name: str,
    timestep: float,
):
    diags = {}
    delp_before = before[DELP]
    delp_after = after[DELP]
    # Compute statistics
    for variable in tendency_variables:
        diag_name = f"tendency_of_{variable}_due_to_{name}"
        diags[diag_name] = (after[variable] - before[variable]) / timestep
        if "units" in before[variable].attrs:
            diags[diag_name].attrs["units"] = before[variable].units + "/s"

    for variable in storage_variables:
        path_before = vcm.mass_integrate(before[variable], delp_before, "z")
        path_after = vcm.mass_integrate(after[variable], delp_after, "z")

        diag_name = f"storage_of_{variable}_path_due_to_{name}"
        diags[diag_name] = (path_after - path_before) / timestep
        if "units" in before[variable].attrs:
            diags[diag_name].attrs[
                "units"] = before[variable].units + " kg/m**2/s"

    mass_change = (delp_after - delp_before).sum("z") / timestep
    mass_change.attrs["units"] = "Pa/s"
    diags[f"storage_of_mass_due_to_{name}"] = mass_change
    return diags
Пример #2
0
def compute_baseline_diagnostics(state: State) -> Diagnostics:

    return dict(
        water_vapor_path=vcm.mass_integrate(state[SPHUM], state[DELP], dim="z")
        .assign_attrs(units="mm")
        .assign_attrs(description="column integrated water vapor"),
        physics_precip=(state[PHYSICS_PRECIP_RATE])
        .assign_attrs(units="kg/m^2/s")
        .assign_attrs(
            description="surface precipitation rate due to parameterized physics"
        ),
    )
Пример #3
0
def water_vapor_path(self):
    try:
        return self._mapper["water_vapor_path"]
    except KeyError:
        da = vcm.mass_integrate(
            self._mapper["specific_humidity"],
            self._mapper["pressure_thickness_of_atmospheric_layer"],
            dim="z",
        )
        return da.assign_attrs(
            {"long_name": "column integrated water vapor", "units": "mm"}
        )
Пример #4
0
def compute_ml_momentum_diagnostics(state: State, tendency: State) -> Diagnostics:
    delp = state[DELP]

    dQu = tendency.get("dQu", xr.zeros_like(delp))
    dQv = tendency.get("dQv", xr.zeros_like(delp))
    column_integrated_dQu = vcm.mass_integrate(dQu, delp, "z")
    column_integrated_dQv = vcm.mass_integrate(dQv, delp, "z")
    return dict(
        dQu=dQu.assign_attrs(units="m s^-2").assign_attrs(
            description="zonal wind tendency due to ML"
        ),
        dQv=dQv.assign_attrs(units="m s^-2").assign_attrs(
            description="meridional wind tendency due to ML"
        ),
        column_integrated_dQu_stress=column_integrated_dQu.assign_attrs(
            units="Pa", description="column integrated zonal wind tendency due to ML",
        ),
        column_integrated_dQv_stress=column_integrated_dQv.assign_attrs(
            units="Pa",
            description="column integrated meridional wind tendency due to ML",
        ),
    )
Пример #5
0
    def _apply_physics(self) -> Diagnostics:
        self._log_debug(f"Physics Step (apply)")
        self._fv3gfs.apply_physics()

        micro = self._fv3gfs.get_diagnostic_by_name(
            "tendency_of_specific_humidity_due_to_microphysics").data_array
        delp = self._state[DELP]
        return {
            "storage_of_specific_humidity_path_due_to_microphysics":
            vcm.mass_integrate(micro, delp, "z"),
            "evaporation":
            self._state["evaporation"],
            "cnvprcp_after_physics":
            self._fv3gfs.get_diagnostic_by_name("cnvprcp").data_array,
            "total_precip_after_physics":
            self._state[TOTAL_PRECIP],
        }
Пример #6
0
def insert_column_integrated_vars(
    ds: xr.Dataset, column_integrated_vars: Sequence[str]
) -> xr.Dataset:
    """Insert column integrated (<*>) terms,
    really a wrapper around vcm.calc.thermo funcs"""

    for var in column_integrated_vars:
        column_integrated_name = f"column_integrated_{var}"
        if "Q1" in var:
            da = vcm.column_integrated_heating_from_isochoric_transition(
                ds[var], ds[DELP]
            )
        elif "Q2" in var:
            da = -vcm.minus_column_integrated_moistening(ds[var], ds[DELP])
            da = da.assign_attrs(
                {"long_name": "column integrated moistening", "units": "mm/day"}
            )
        else:
            da = vcm.mass_integrate(ds[var], ds[DELP], dim="z")
        ds = ds.assign({column_integrated_name: da})

    return ds
Пример #7
0
    def __call__(self, time, state):

        diagnostics: Diagnostics = {}
        delp = state[DELP]

        prediction: State = predict(self.model, state)

        tendency, state_updates = {}, {}
        for key, value in prediction.items():
            if is_state_update_variable(key, state):
                state_updates[key] = value
            else:
                tendency[key] = value

        for name in state_updates.keys():
            diagnostics[name] = state_updates[name]

        dQ1_initial = tendency.get("dQ1", xr.zeros_like(state[SPHUM]))
        dQ2_initial = tendency.get("dQ2", xr.zeros_like(state[SPHUM]))

        dQ1_updated, dQ2_updated = non_negative_sphum(
            state[SPHUM],
            dQ1_initial,
            dQ2_initial,
            dt=self.timestep,
        )

        if "dQ1" in tendency:
            if self.hydrostatic:
                heating = vcm.column_integrated_heating_from_isobaric_transition(
                    dQ1_updated - tendency["dQ1"], delp, "z")
            else:
                heating = vcm.column_integrated_heating_from_isochoric_transition(
                    dQ1_updated - tendency["dQ1"], delp, "z")
            heating = heating.assign_attrs(
                long_name=
                "Change in ML column heating due to non-negative specific "
                "humidity limiter")
            diagnostics.update({
                "column_integrated_dQ1_change_non_neg_sphum_constraint":
                heating
            })
            tendency.update({"dQ1": dQ1_updated})
        if "dQ2" in tendency:
            moistening = vcm.mass_integrate(dQ2_updated - tendency["dQ2"],
                                            delp,
                                            dim="z")
            moistening = moistening.assign_attrs(
                units="kg/m^2/s",
                long_name=
                "Change in ML column moistening due to non-negative specific "
                "humidity limiter",
            )
            diagnostics.update({
                "column_integrated_dQ2_change_non_neg_sphum_constraint":
                moistening
            })
            tendency.update({"dQ2": dQ2_updated})

        diagnostics["specific_humidity_limiter_active"] = xr.where(
            dQ2_initial != dQ2_updated, 1, 0)

        return (
            tendency,
            diagnostics,
            state_updates,
        )
Пример #8
0
def compute_diagnostics(
    state: State, tendency: State, label: str, hydrostatic: bool
) -> Diagnostics:
    delp = state[DELP]
    temperature_tendency_name = "dQ1"
    humidity_tendency_name = "dQ2"

    temperature_tendency = tendency.get(temperature_tendency_name, xr.zeros_like(delp))
    humidity_tendency = tendency.get(humidity_tendency_name, xr.zeros_like(delp))

    # compute column-integrated diagnostics
    if hydrostatic:
        net_heating = vcm.column_integrated_heating_from_isobaric_transition(
            temperature_tendency, delp, "z"
        )
    else:
        net_heating = vcm.column_integrated_heating_from_isochoric_transition(
            temperature_tendency, delp, "z"
        )
    diags: Diagnostics = {
        f"net_moistening_due_to_{label}": vcm.mass_integrate(
            humidity_tendency, delp, dim="z"
        ).assign_attrs(
            units="kg/m^2/s",
            description=f"column integrated moisture tendency due to {label}",
        ),
        f"column_heating_due_to_{label}": net_heating.assign_attrs(
            units="W/m^2"
        ).assign_attrs(description=f"column integrated heating due to {label}"),
    }
    delp_tendency = STATE_NAME_TO_TENDENCY[DELP]
    if delp_tendency in tendency:
        net_mass_tendency = vcm.mass_integrate(
            xr.ones_like(tendency[delp_tendency]), tendency[delp_tendency], dim="z"
        ).assign_attrs(
            units="kg/m^2/s",
            description=f"column-integrated mass tendency due to {label}",
        )
        diags[f"net_mass_tendency_due_to_{label}"] = net_mass_tendency

    # add 3D tendencies to diagnostics
    if label == "nudging":
        diags_3d: Mapping[Hashable, xr.DataArray] = {
            f"{TENDENCY_TO_STATE_NAME[k]}_tendency_due_to_nudging": v
            for k, v in tendency.items()
        }
    elif label == "machine_learning":
        diags_3d = {
            "dQ1": temperature_tendency.assign_attrs(units="K/s").assign_attrs(
                description=f"air temperature tendency due to {label}"
            ),
            "dQ2": humidity_tendency.assign_attrs(units="kg/kg/s").assign_attrs(
                description=f"specific humidity tendency due to {label}"
            ),
        }
    diags.update(diags_3d)

    # add 3D state to diagnostics for backwards compatibility
    diags.update({TEMP: state[TEMP], SPHUM: state[SPHUM], DELP: state[DELP]})

    return diags