diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8f8ebe2c..eb4ed2fa 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,18 +21,18 @@ repos: - repo: https://github.com/henryiii/validate-pyproject-schema-store - rev: 2026.07.17 + rev: 2026.07.20 hooks: - id: validate-pyproject - repo: https://github.com/astral-sh/uv-pre-commit - rev: 0.11.29 + rev: 0.11.32 hooks: - id: uv-lock - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.15.22 + rev: v0.16.0 hooks: # Run the linter. - id: ruff diff --git a/adept/_base_.py b/adept/_base_.py index aa21bb83..8c7dd396 100644 --- a/adept/_base_.py +++ b/adept/_base_.py @@ -97,7 +97,6 @@ def init_diffeqsolve(self) -> dict: A dictionary of the differential equation solver quantities """ - pass def get_derived_quantities(self) -> dict: """ @@ -109,7 +108,6 @@ def get_derived_quantities(self) -> dict: An updated configuration dictionary """ - pass def get_solver_quantities(self): """ @@ -121,7 +119,6 @@ def get_solver_quantities(self): An updated configuration dictionary """ - pass def get_save_func(self): """ @@ -132,7 +129,6 @@ def get_save_func(self): This dictionary is set as a class attribute for the ``ADEPTModule`` and are used in the ``__call__`` function """ - pass def init_state_and_args(self): """ diff --git a/adept/_lpse2d/core/vector_field.py b/adept/_lpse2d/core/vector_field.py index 1c8e1930..65843443 100644 --- a/adept/_lpse2d/core/vector_field.py +++ b/adept/_lpse2d/core/vector_field.py @@ -41,7 +41,7 @@ def __init__(self, cfg): def _unpack_y_(self, y: dict[str, Array]) -> dict[str, Array]: new_y = {} - for k in y.keys(): + for k in y: if k in self.complex_state_vars: new_y[k] = y[k].view(jnp.complex128) else: @@ -49,7 +49,7 @@ def _unpack_y_(self, y: dict[str, Array]) -> dict[str, Array]: return new_y def _pack_y_(self, y: dict[str, Array], new_y: dict[str, Array]) -> tuple[dict[str, Array], dict[str, Array]]: - for k in y.keys(): + for k in y: y[k] = y[k].view(jnp.float64) new_y[k] = new_y[k].view(jnp.float64) diff --git a/adept/_lpse2d/helpers.py b/adept/_lpse2d/helpers.py index 66623791..3dc11b89 100644 --- a/adept/_lpse2d/helpers.py +++ b/adept/_lpse2d/helpers.py @@ -294,23 +294,21 @@ def get_solver_quantities(cfg: dict) -> dict: cfg_grid = { **cfg_grid, - **{ - "x": np.linspace( - cfg_grid["xmin"] + cfg_grid["dx"] / 2, - cfg_grid["xmax"] - cfg_grid["dx"] / 2, - cfg_grid["nx"], - ), - "y": np.linspace( - cfg_grid["ymin"] + cfg_grid["dy"] / 2, - cfg_grid["ymax"] - cfg_grid["dy"] / 2, - cfg_grid["ny"], - ), - "t": np.linspace(0, cfg_grid["tmax"], cfg_grid["nt"]), - "kx": np.fft.fftfreq(cfg_grid["nx"], d=cfg_grid["dx"] / 2.0 / np.pi), - "kxr": np.fft.rfftfreq(cfg_grid["nx"], d=cfg_grid["dx"] / 2.0 / np.pi), - "ky": np.fft.fftfreq(cfg_grid["ny"], d=cfg_grid["dy"] / 2.0 / np.pi), - "kyr": np.fft.rfftfreq(cfg_grid["ny"], d=cfg_grid["dy"] / 2.0 / np.pi), - }, + "x": np.linspace( + cfg_grid["xmin"] + cfg_grid["dx"] / 2, + cfg_grid["xmax"] - cfg_grid["dx"] / 2, + cfg_grid["nx"], + ), + "y": np.linspace( + cfg_grid["ymin"] + cfg_grid["dy"] / 2, + cfg_grid["ymax"] - cfg_grid["dy"] / 2, + cfg_grid["ny"], + ), + "t": np.linspace(0, cfg_grid["tmax"], cfg_grid["nt"]), + "kx": np.fft.fftfreq(cfg_grid["nx"], d=cfg_grid["dx"] / 2.0 / np.pi), + "kxr": np.fft.rfftfreq(cfg_grid["nx"], d=cfg_grid["dx"] / 2.0 / np.pi), + "ky": np.fft.fftfreq(cfg_grid["ny"], d=cfg_grid["dy"] / 2.0 / np.pi), + "kyr": np.fft.rfftfreq(cfg_grid["ny"], d=cfg_grid["dy"] / 2.0 / np.pi), } one_over_kx = np.zeros_like(cfg_grid["kx"]) @@ -483,7 +481,7 @@ def get_density_profile(cfg: dict) -> Array: def plot_fields(fields, td): t_skip = int(fields.coords["t (ps)"].data.size // 8) - t_skip = t_skip if t_skip > 1 else 1 + t_skip = max(1, t_skip) tslice = slice(0, -1, t_skip) dx = fields.coords["x (um)"].data[1] - fields.coords["x (um)"].data[0] @@ -535,7 +533,7 @@ def plot_fields(fields, td): def plot_kt(kfields, td): t_skip = int(kfields.coords["t (ps)"].data.size // 6) - t_skip = t_skip if t_skip > 1 else 1 + t_skip = max(1, t_skip) tslice = slice(0, -1, t_skip) for abs_kmax in [2.5, 1.25]: diff --git a/adept/_spectrax1d/base_module.py b/adept/_spectrax1d/base_module.py index d0596281..63aa25b8 100644 --- a/adept/_spectrax1d/base_module.py +++ b/adept/_spectrax1d/base_module.py @@ -819,8 +819,7 @@ def _save_scalar_outputs(self, scalar_outputs: dict, td: str) -> None: with open(os.path.join(td, "scalar_outputs.txt"), "w") as f: f.write("Spectrax Scalar Outputs\n") f.write("=" * 50 + "\n\n") - for key, value in sorted(scalar_outputs.items()): - f.write(f"{key}: {value}\n") + f.writelines(f"{key}: {value}\n" for key, value in sorted(scalar_outputs.items())) def _process_distribution_function(self, Ck, t_array, Nn, Nm, Np, Nx, Ny, Nz, td: str) -> None: """Process and save distribution function (Hermite-Fourier coefficients).""" diff --git a/adept/_spectrax1d/nonlinear_vector_field.py b/adept/_spectrax1d/nonlinear_vector_field.py index cb47d9d8..94f1f079 100644 --- a/adept/_spectrax1d/nonlinear_vector_field.py +++ b/adept/_spectrax1d/nonlinear_vector_field.py @@ -305,7 +305,7 @@ def _generate_density_noise(self, t: float, Nx: int, alpha: float, amplitude: fl def _unpack_y_(self, y: dict[str, Array]) -> dict[str, Array]: """Unpack state from float64 views to complex128.""" new_y = {} - for k in y.keys(): + for k in y: if k in self.complex_state_vars: new_y[k] = y[k].view(jnp.complex128) else: diff --git a/adept/_tf1d/modules.py b/adept/_tf1d/modules.py index 9816785d..18613cea 100644 --- a/adept/_tf1d/modules.py +++ b/adept/_tf1d/modules.py @@ -149,14 +149,12 @@ def get_solver_quantities(self): cfg_grid = { **cfg_grid, - **{ - "x": jnp.linspace( - cfg_grid["xmin"] + cfg_grid["dx"] / 2, cfg_grid["xmax"] - cfg_grid["dx"] / 2, cfg_grid["nx"] - ), - "t": jnp.linspace(0, cfg_grid["tmax"], cfg_grid["nt"]), - "kx": jnp.fft.fftfreq(cfg_grid["nx"], d=cfg_grid["dx"]) * 2.0 * np.pi, - "kxr": jnp.fft.rfftfreq(cfg_grid["nx"], d=cfg_grid["dx"]) * 2.0 * np.pi, - }, + "x": jnp.linspace( + cfg_grid["xmin"] + cfg_grid["dx"] / 2, cfg_grid["xmax"] - cfg_grid["dx"] / 2, cfg_grid["nx"] + ), + "t": jnp.linspace(0, cfg_grid["tmax"], cfg_grid["nt"]), + "kx": jnp.fft.fftfreq(cfg_grid["nx"], d=cfg_grid["dx"]) * 2.0 * np.pi, + "kxr": jnp.fft.rfftfreq(cfg_grid["nx"], d=cfg_grid["dx"]) * 2.0 * np.pi, } one_over_kx = np.zeros_like(cfg_grid["kx"]) diff --git a/adept/_vlasov1d/helpers.py b/adept/_vlasov1d/helpers.py index 534047ac..6436d515 100644 --- a/adept/_vlasov1d/helpers.py +++ b/adept/_vlasov1d/helpers.py @@ -216,7 +216,7 @@ def post_process(result: Solution, cfg: dict, td: str, args: dict): species_dir = os.path.join(fields_base_dir, species_name) t_skip = int(species_xr.coords["t"].data.size // 8) - t_skip = t_skip if t_skip > 1 else 1 + t_skip = max(1, t_skip) tslice = slice(0, -1, t_skip) for nm, fld in species_xr.items(): @@ -247,7 +247,7 @@ def post_process(result: Solution, cfg: dict, td: str, args: dict): shared_xr = fields_dict["fields"] t_skip = int(shared_xr.coords["t"].data.size // 8) - t_skip = t_skip if t_skip > 1 else 1 + t_skip = max(1, t_skip) tslice = slice(0, -1, t_skip) for nm, fld in shared_xr.items(): @@ -311,7 +311,7 @@ def post_process(result: Solution, cfg: dict, td: str, args: dict): # Select ~8 time snapshots for facet plot t_skip = int(f_species.coords["t"].data.size // 8) - t_skip = t_skip if t_skip > 1 else 1 + t_skip = max(1, t_skip) tslice = slice(0, -1, t_skip) # Create f(x,v) phase space plot diff --git a/adept/_vlasov1d/solvers/vector_field.py b/adept/_vlasov1d/solvers/vector_field.py index 76effe02..4cda2f98 100644 --- a/adept/_vlasov1d/solvers/vector_field.py +++ b/adept/_vlasov1d/solvers/vector_field.py @@ -244,11 +244,11 @@ def __call__( if self.vlasov_dfdt: # Compute diagnostics for each species - for species_name in f_dict.keys(): + for species_name in f_dict: diags[f"diag-vlasov-dfdt-{species_name}"] = (f_vlasov[species_name] - f_dict[species_name]) / self.dt if self.fp_dfdt: # Compute diagnostics for each species - for species_name in f_dict.keys(): + for species_name in f_dict: diags[f"diag-fp-dfdt-{species_name}"] = (f_fp[species_name] - f_vlasov[species_name]) / self.dt return e, f_fp, diags diff --git a/adept/_vlasov1d/storage.py b/adept/_vlasov1d/storage.py index 6899e049..4db29f4e 100644 --- a/adept/_vlasov1d/storage.py +++ b/adept/_vlasov1d/storage.py @@ -23,7 +23,7 @@ def store_fields(cfg: dict, binary_dir: str, fields: dict, this_t: np.ndarray, p result = {} # Shared field keys at top level shared_field_keys = {"e", "de", "a", "prev_a", "pond", "ep", "em"} - species_names = [k for k in fields.keys() if k not in shared_field_keys] + species_names = [k for k in fields if k not in shared_field_keys] # Store species-specific moments for species_name in species_names: @@ -82,9 +82,7 @@ def store_f(cfg: dict, this_t: dict, td: str, ys: dict) -> dict: :param ys: :return: dict mapping save_key -> xr.Dataset """ - dist_save_keys = [ - k for k in ys.keys() if "_species_name" in cfg["save"].get(k, {}) or "_diag" in cfg["save"].get(k, {}) - ] + dist_save_keys = [k for k in ys if "_species_name" in cfg["save"].get(k, {}) or "_diag" in cfg["save"].get(k, {})] result = {} for save_key in dist_save_keys: @@ -189,10 +187,7 @@ def dist_save_func(t, y, args): fkx = jnp.abs(jnp.fft.rfft(y[dist_key], axes=0)) return interp2d(kxq_flat, vq_flat, axes["kx"], axes["v"], fkx, method="linear").reshape(out_shape) - elif {"t", "x", "kv"} == set(dist_save_config.keys()): - pass - - elif {"t", "kx", "kv"} == set(dist_save_config.keys()): + elif {"t", "x", "kv"} == set(dist_save_config.keys()) or {"t", "kx", "kv"} == set(dist_save_config.keys()): pass else: raise NotImplementedError diff --git a/adept/_vlasov2d/helpers.py b/adept/_vlasov2d/helpers.py index 35f5475b..a1edf32e 100644 --- a/adept/_vlasov2d/helpers.py +++ b/adept/_vlasov2d/helpers.py @@ -217,7 +217,7 @@ def _save_xy_facet(fld, path: str, n_panels: int = 8) -> None: vmax = 1.0 vmin = -vmax - ncols = 4 if n_panels >= 4 else n_panels + ncols = min(4, n_panels) nrows = int(np.ceil(n_panels / ncols)) g = panels.plot( col="t", diff --git a/adept/_vlasov2d/storage.py b/adept/_vlasov2d/storage.py index e3734c50..e646c6c8 100644 --- a/adept/_vlasov2d/storage.py +++ b/adept/_vlasov2d/storage.py @@ -13,7 +13,7 @@ def store_fields(cfg: dict, binary_dir: str, fields: dict, this_t: np.ndarray, p """Persist saved fields/moments to netCDF and return them as xr.Datasets.""" result = {} shared_keys = {"ex", "ey", "bz", "jx_driver", "jy_driver"} - species_names = [k for k in fields.keys() if k not in shared_keys] + species_names = [k for k in fields if k not in shared_keys] x_coord = cfg["grid"]["x"] y_coord = cfg["grid"]["y"] @@ -40,7 +40,7 @@ def store_fields(cfg: dict, binary_dir: str, fields: dict, this_t: np.ndarray, p def store_f(cfg: dict, this_t: dict, td: str, ys: dict) -> dict: """Persist distribution snapshots to netCDF.""" - save_keys = [k for k in ys.keys() if "_species_name" in cfg["save"].get(k, {})] + save_keys = [k for k in ys if "_species_name" in cfg["save"].get(k, {})] binary_dir = os.path.join(td, "binary") os.makedirs(binary_dir, exist_ok=True) diff --git a/adept/mlflow_logging.py b/adept/mlflow_logging.py index 49ceecb2..4ec8ebae 100644 --- a/adept/mlflow_logging.py +++ b/adept/mlflow_logging.py @@ -170,7 +170,6 @@ def setup(self, *args, mlflow_run_id=None, **kwargs): - `*args`: Any remaining positional arguments to `self.__call__` - `*kwargs`: Any remaining keyword arguments to `self.__call__` """ - pass @abstractmethod def call(self, *args, setup_result=None, mlflow_run_id=None, **kwargs): @@ -183,7 +182,6 @@ def call(self, *args, setup_result=None, mlflow_run_id=None, **kwargs): - `*args`: Any remaining positional arguments to `self.__call__` - `*kwargs`: Any remaining keyword arguments to `self.__call__` """ - pass @abstractmethod def pre_logging(self, *args, setup_result=None, mlflow_run_id=None, **kwargs): @@ -196,7 +194,6 @@ def pre_logging(self, *args, setup_result=None, mlflow_run_id=None, **kwargs): - `*args`: Any remaining positional arguments to `self.__call__` - `*kwargs`: Any remaining keyword arguments to `self.__call__` """ - pass @abstractmethod def post_logging(self, result, *args, setup_result=None, mlflow_run_id=None, **kwargs): @@ -210,4 +207,3 @@ def post_logging(self, result, *args, setup_result=None, mlflow_run_id=None, **k - `*args`: Any remaining positional arguments to `self.__call__` - `*kwargs`: Any remaining keyword arguments to `self.__call__` """ - pass diff --git a/adept/normalization.py b/adept/normalization.py index ae23bbc2..4ab7727f 100644 --- a/adept/normalization.py +++ b/adept/normalization.py @@ -53,7 +53,7 @@ def speed_of_light_norm(self) -> float: return (UREG.Quantity(1, "speed_of_light").to("m/s") / self.v0).to("").magnitude -def normalize(s: float | int | str, norm: PlasmaNormalization | None = None, dim: str = "x") -> float: +def normalize(s: float | str, norm: PlasmaNormalization | None = None, dim: str = "x") -> float: if isinstance(s, (int, float)) and not isinstance(s, bool): return float(s) diff --git a/adept/vfp1d/base.py b/adept/vfp1d/base.py index 7f54f490..aca18cff 100644 --- a/adept/vfp1d/base.py +++ b/adept/vfp1d/base.py @@ -161,7 +161,7 @@ def init_state_and_args(self) -> dict: state = {"f0": f0} # not currently necessary but kept for completeness for il in range(1, grid.nl + 1): - for im in range(0, il + 1): + for im in range(il + 1): state[f"f{il}{im}"] = jnp.zeros((grid.nx + 1, grid.nv)) state["f10"] = f10 diff --git a/adept/vfp1d/fokker_planck.py b/adept/vfp1d/fokker_planck.py index 910a0975..98c1543d 100644 --- a/adept/vfp1d/fokker_planck.py +++ b/adept/vfp1d/fokker_planck.py @@ -510,7 +510,6 @@ def __call__(self, Z, ni, f0, f10, dt, include_ee_offdiag_explicitly=True): if self.full_aniso_ee: ee_diag, ee_lower, ee_upper = self.get_ee_diagonal_contrib(f0) pad_f0 = jnp.concatenate([f0[:, 1::-1], f0], axis=1) - # d2dv2 = 0.5 / v * jnp.gradient(jnp.gradient(pad_f0, dv, axis=1), dv, axis=1)[:, 2:] ddv = v**-2.0 * jnp.gradient(pad_f0, dv, axis=1)[:, 2:] diff --git a/adept/vfp1d/storage.py b/adept/vfp1d/storage.py index be22081d..d15e2f7f 100644 --- a/adept/vfp1d/storage.py +++ b/adept/vfp1d/storage.py @@ -236,7 +236,7 @@ def post_process(soln: Solution, cfg: dict, td: str, args: dict | None = None) - if k.startswith("field"): fields_xr = store_fields(cfg, binary_dir, soln.ys[k], soln.ts[k], k) t_skip = int(fields_xr.coords["t (ps)"].data.size // 8) - t_skip = t_skip if t_skip > 1 else 1 + t_skip = max(1, t_skip) tslice = slice(0, -1, t_skip) for nm, fld in fields_xr.items(): @@ -274,7 +274,7 @@ def post_process(soln: Solution, cfg: dict, td: str, args: dict | None = None) - f_xr = store_f(cfg, soln.ts, td, soln.ys) t_skip = int(f_xr.coords["t (ps)"].data.size // 4) - t_skip = t_skip if t_skip > 1 else 1 + t_skip = max(1, t_skip) tslice = slice(0, -1, t_skip) for k in ["f0", "f10"]: diff --git a/adept/vlasov1d2v/helpers.py b/adept/vlasov1d2v/helpers.py index bf0e7f4f..501a5b41 100644 --- a/adept/vlasov1d2v/helpers.py +++ b/adept/vlasov1d2v/helpers.py @@ -242,19 +242,15 @@ def get_solver_quantities(cfg: dict) -> dict: cfg_grid = { **cfg_grid, - **{ - "x": jnp.linspace( - cfg_grid["xmin"] + cfg_grid["dx"] / 2, cfg_grid["xmax"] - cfg_grid["dx"] / 2, cfg_grid["nx"] - ), - "t": jnp.linspace(0, cfg_grid["tmax"], cfg_grid["nt"]), - "v": jnp.linspace( - -cfg_grid["vmax"] + cfg_grid["dv"] / 2, cfg_grid["vmax"] - cfg_grid["dv"] / 2, cfg_grid["nv"] - ), - "kx": jnp.fft.fftfreq(cfg_grid["nx"], d=cfg_grid["dx"]) * 2.0 * np.pi, - "kxr": jnp.fft.rfftfreq(cfg_grid["nx"], d=cfg_grid["dx"]) * 2.0 * np.pi, - "kv": jnp.fft.fftfreq(cfg_grid["nv"], d=cfg_grid["dv"]) * 2.0 * np.pi, - "kvr": jnp.fft.rfftfreq(cfg_grid["nv"], d=cfg_grid["dv"]) * 2.0 * np.pi, - }, + "x": jnp.linspace(cfg_grid["xmin"] + cfg_grid["dx"] / 2, cfg_grid["xmax"] - cfg_grid["dx"] / 2, cfg_grid["nx"]), + "t": jnp.linspace(0, cfg_grid["tmax"], cfg_grid["nt"]), + "v": jnp.linspace( + -cfg_grid["vmax"] + cfg_grid["dv"] / 2, cfg_grid["vmax"] - cfg_grid["dv"] / 2, cfg_grid["nv"] + ), + "kx": jnp.fft.fftfreq(cfg_grid["nx"], d=cfg_grid["dx"]) * 2.0 * np.pi, + "kxr": jnp.fft.rfftfreq(cfg_grid["nx"], d=cfg_grid["dx"]) * 2.0 * np.pi, + "kv": jnp.fft.fftfreq(cfg_grid["nv"], d=cfg_grid["dv"]) * 2.0 * np.pi, + "kvr": jnp.fft.rfftfreq(cfg_grid["nv"], d=cfg_grid["dv"]) * 2.0 * np.pi, } # config axes @@ -370,7 +366,7 @@ def post_process(result, cfg: dict, td: str): if k.startswith("field"): fields_xr = store_fields(cfg, binary_dir, result.ys[k], result.ts[k], k) t_skip = int(fields_xr.coords["t"].data.size // 8) - t_skip = t_skip if t_skip > 1 else 1 + t_skip = max(1, t_skip) tslice = slice(0, -1, t_skip) for nm, fld in fields_xr.items(): diff --git a/tests/test_base/test_mlflow_logging.py b/tests/test_base/test_mlflow_logging.py index 1e3a5d3f..0e48521d 100644 --- a/tests/test_base/test_mlflow_logging.py +++ b/tests/test_base/test_mlflow_logging.py @@ -234,7 +234,6 @@ def test_mlflow_callback_preserves_function_metadata(): @mlflow_callback def my_logging_func(value, *, mlflow_run_id: str): """This is my docstring.""" - pass assert my_logging_func.__name__ == "my_logging_func" assert my_logging_func.__doc__ == """This is my docstring.""" diff --git a/tests/test_vfp1d/test_fp_relaxation.py b/tests/test_vfp1d/test_fp_relaxation.py index bde978e8..edb82d27 100644 --- a/tests/test_vfp1d/test_fp_relaxation.py +++ b/tests/test_vfp1d/test_fp_relaxation.py @@ -194,6 +194,6 @@ def make_vector_field( grid=vfp_grid, model=get_model(model_name, vfp_grid.v, vfp_grid.dv), scheme=get_scheme(scheme_map.get(scheme_name, scheme_name.lower()), vfp_grid.dv), - sc_beta=SelfConsistentBetaConfig(max_steps=sc_iterations if sc_iterations > 0 else 0), + sc_beta=SelfConsistentBetaConfig(max_steps=max(0, sc_iterations)), ) return F0CollisionsVectorField(collisions=collisions, dt=dt) diff --git a/tests/test_vlasov1d/test_landau_damping.py b/tests/test_vlasov1d/test_landau_damping.py index ce5c64a5..64277789 100644 --- a/tests/test_vlasov1d/test_landau_damping.py +++ b/tests/test_vlasov1d/test_landau_damping.py @@ -42,9 +42,7 @@ def test_single_resonance(real_or_imag, time, field, edfdv, request): # Mark flaky test as xfail if (real_or_imag, time, field, edfdv) == ("imag", "leapfrog", "ampere", "cubic-spline"): request.node.add_marker(pytest.mark.xfail(reason="Fails mysteriously with float64")) - if (time == "sixth") and (field == "ampere"): - print("not implemented - skipping test") - elif (time == "sixth") and (field == "hampere"): + if ((time == "sixth") and (field == "ampere")) or ((time == "sixth") and (field == "hampere")): print("not implemented - skipping test") else: with open("tests/test_vlasov1d/configs/resonance.yaml") as file: