NEDAS.core.perturb module
- class NEDAS.core.perturb.PerturbField(**kwargs)[source]
Bases:
objectGenerates and applies perturbation on given 2D field(s)
- mask: ndarray
- perturb_type: str
- other_opts: list[str] = []
- params: dict[str, dict[str, Any]] = {}
- grid: RegularGrid | IrregularGrid | Grid1D
- perturb_methods: dict[str, Callable]
- generate_perturb(grid: RegularGrid | IrregularGrid | Grid1D, fields: dict[str, ndarray], prev_perturb: dict[str, Any], dt: float = 1, n: int = 0) dict[str, ndarray][source]
Add random perturbation to the given 2D fields
- Parameters:
grid (GridType) – Grid object describing the 2d domain
fields (dict[str, np.ndarray]) – the input fields
prev_perturb (dict[str, Any]) – previous perturbation data, dict[str, None] if unavailable
dt (float) – interval (hours) between time steps
n (int)
- Returns:
the generated perturbations
- Return type:
dict[str, np.ndarray]
- add_perturb(fields: dict[str, ndarray], perturb: dict[str, ndarray], **kwargs) dict[str, ndarray][source]
Add perturbations to each field
- perturb_random_gaussian(rec: dict[str, Any], s: int) ndarray[source]
Generate a random perturbation using the Gaussian random field method
- perturb_random_powerlaw(rec: dict[str, Any], s: int) ndarray[source]
Generate a random perturbation using the powerlaw method
- perturb_random_displace(rec: dict[str, Any], s: int) ndarray[source]
Generate a random perturbation using the displacement method (returns a vector field)
Create perturbations that are correlated in time
- make_wind_perturb_from_press(perturb: dict[str, ndarray]) dict[str, ndarray][source]
Legacy option in TOPAZ prsflg==1,2 options in force_perturb program, reproduced here. Expecting the vnames ‘atmos_surf_press’ for pressure field and ‘atmos_surf_velocity’ for the wind field. Derive the wind perturbation from pressure perturbations, so that they are in wind-pressure relation (prsflg==1) Additionally, derived wind perturbations are rescaled to match the specified amp (prsflg==2)
- class NEDAS.core.perturb.Perturbation(c: Context)[source]
Bases:
objectPerturbation top-level manager
- nfld: int = 0
- perturb: dict[str, Any] = {}
- task_list: dict[int, list[dict]] = {}
- init_file_locks(c: Context) None[source]
Initialize file locks for nc-backed perturb variables (e.g. iced, iceh).
Mirrors the updator pattern: register only the output file paths THIS rank will personally write, then call build_file_locks(), which does its own internal allgather to reconstruct the full per-file writer ordering (point-to-point handoff chain, see utils/parallel.py).
The file-collection loop is wrapped in try/except so that a rank that fails mid-loop still participates in the collective allgather (inside build_file_locks) and Barrier, preventing an MPI deadlock. Any error is re-raised after the barrier so the outer try/except in __call__ can handle it uniformly.
- rec_dt(model, variable_list: list) float[source]
Return the shared dt for all variables in a perturb record.
Raises ValueError if variables have different dt, since one time loop cannot serve variables with different temporal resolutions.
- nstep(c: Context, model, dt: float) int[source]
Number of time steps to perturb for a variable with the given dt.
A variable is BC/forcing if its dt is strictly less than the model restart_dt (sub-restart temporal resolution). It is perturbed at every dt step over the forecast period. IC/restart variables are perturbed once at t=0.
Uses model.restart_dt as the threshold when available; falls back to cycle_period so models without restart_dt get the conservative nstep=1.
- prepare_perturb_dir(c)[source]
Prepare and clear the directory where perturbation data will be stored (offline mode)
- save_perturb_data(c: Context, **rec)[source]
Save a copy of perturbation data, for use by the next analysis cycle