From f0e131a8fc57fb367985a95806a38c2a7e44d9bf Mon Sep 17 00:00:00 2001 From: codedbyasim Date: Sat, 28 Mar 2026 18:06:21 +0500 Subject: [PATCH 1/3] refactor: replace print() with loguru logger for structured logging --- CHANGELOG.md | 1 + .../compute_standardization_stats.py | 17 +++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe66d2136..fca43415b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Replace remaining `print()` calls with `loguru` `logger.info()` in `compute_standardization_stats.py` for structured and consistent logging @[yourusername] - Change the default ensemble-loading behavior in `WeatherDataset` / `WeatherDataModule` to use all ensemble members as independent samples for ensemble datastores (with matching ensemble-member selection for forcing when available); single-member behavior now requires explicitly opting in via `--load_single_member` [\#332](https://github.com/mllam/neural-lam/pull/332) @kshirajahere - Refactor graph loading: move zero-indexing out of the model and update plotting to prepare using the research-branch graph I/O [\#184](https://github.com/mllam/neural-lam/pull/184) @zweihuehner - Replace `print()`-based `rank_zero_print` with `loguru` `logger.info()` for structured log-level control ([#33](https://github.com/mllam/neural-lam/issues/33)) diff --git a/neural_lam/datastore/npyfilesmeps/compute_standardization_stats.py b/neural_lam/datastore/npyfilesmeps/compute_standardization_stats.py index 7dbcc7ef8..97bd3cb7b 100644 --- a/neural_lam/datastore/npyfilesmeps/compute_standardization_stats.py +++ b/neural_lam/datastore/npyfilesmeps/compute_standardization_stats.py @@ -8,6 +8,7 @@ # Third-party import torch import torch.distributed as dist +from loguru import logger from torch.utils.data.distributed import DistributedSampler from tqdm import tqdm @@ -78,10 +79,10 @@ def setup(rank, world_size): # pylint: disable=redefined-outer-name ) master_node = hostname_lines[0].strip() else: - print( - "\033[91mCareful, you are running this script with --distributed " + logger.warning( + "Careful, you are running this script with --distributed " "without any scheduler. In most cases this will result in slower " - "execution and the --distributed flag should be removed.\033[0m" + "execution and the --distributed flag should be removed." ) master_node = "localhost" os.environ["MASTER_ADDR"] = master_node @@ -92,7 +93,7 @@ def setup(rank, world_size): # pylint: disable=redefined-outer-name world_size=world_size, ) if rank == 0: - print( + logger.info( f"Initialized {dist.get_backend()} " f"process group with world size {world_size}." ) @@ -110,7 +111,7 @@ def save_stats( mean = torch.mean(means, dim=0) # (d_features,) second_moment = torch.mean(squares, dim=0) # (d_features,) std = torch.sqrt(second_moment - mean**2) # (d_features,) - print( + logger.info( f"Saving {filename_prefix} mean and std.-dev. to " f"{filename_prefix}_mean.pt and {filename_prefix}_std.pt" ) @@ -132,7 +133,7 @@ def save_stats( flux_mean = torch.mean(flux_means) # (,) flux_second_moment = torch.mean(flux_squares) # (,) flux_std = torch.sqrt(flux_second_moment - flux_mean**2) # (,) - print("Saving flux mean and std.-dev. to flux_stats.pt") + logger.info("Saving flux mean and std.-dev. to flux_stats.pt") torch.save( torch.stack((flux_mean, flux_std)).cpu(), os.path.join(static_dir_path, "flux_stats.pt"), @@ -206,7 +207,7 @@ def main( ) if rank == 0: - print("Computing mean and std.-dev. for parameters...") + logger.info("Computing mean and std.-dev. for parameters...") means, squares, flux_means, flux_squares = [], [], [], [] for init_batch, target_batch, forcing_batch, _ in tqdm(loader): @@ -280,7 +281,7 @@ def main( dist.barrier() if rank == 0: - print("Computing mean and std.-dev. for one-step differences...") + logger.info("Computing mean and std.-dev. for one-step differences...") ds_standard = WeatherDataset( datastore=datastore, split="train", From b63fa9f32778ba7c930c08bf137ce28c171057ae Mon Sep 17 00:00:00 2001 From: codedbyasim Date: Sat, 28 Mar 2026 20:36:21 +0500 Subject: [PATCH 2/3] refactor: split AGENTS.md into human-facing CONTRIBUTING.md and technical AGENTS.md overview --- AGENTS.md | 52 +++++++------------------------------------------ CHANGELOG.md | 1 + CONTRIBUTING.md | 48 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 45 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/AGENTS.md b/AGENTS.md index dcf05d563..a43f7d0af 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,7 @@ # AGENTS.md -Mandatory rules for AI coding agents. Violations will result in rejected PRs. +Mandatory rules and context for AI coding agents. +**Human contributors: Please refer to the [Contributing Guide](docs/contributing/contributing.md).** --- @@ -50,48 +51,9 @@ W&B auto-disabled in tests. `DummyDatastore` used; example data downloaded from --- -## Rules +## Mandate for AI Agents -### Issues - -1. **Search before creating.** Use any of: GitHub UI search, `gh issue list --state all --search ""`, or `curl "https://api.github.com/search/issues?q=+repo:mllam/neural-lam+type:issue"`. Duplicate issues will be closed. -2. **Every PR requires an issue.** No exceptions. Open one first if none exists. -3. **Include minimal example.** Each issue should include a minimal, reproducible example on how to easily recreate a bug, including all necessary module imports and data. Include full traceback if it is a bug-report. - -### Pull Requests - -1. **Search before creating.** Use any of: GitHub UI search, `gh pr list --state all --search ""`, or `curl "https://api.github.com/search/issues?q=+repo:mllam/neural-lam+type:pr"`. If a PR exists for the same issue, contribute there. -2. **Link the issue.** PR body must contain `closes #` or `refs #`. Unlinked PRs will be - rejected. -3. **Use the PR template.** Fill in every section of `.github/pull_request_template.md`. Do not - delete or skip sections. -4. **Read the full issue thread before writing code.** Rejected approaches and prior decisions are - there. Ignoring them wastes everyone's time. -5. **Run pre-commit hooks locally.** Linting needs to be done locally before each new commit with e.g. `uvx pre-commit run --all` -6. **Testing Mandate.** Run `pytests tests/` before opening a PR and if tests fail do not open the PR , fix the failure first. - -### Communication - -- **Terse.** One sentence per point. No preamble. No summaries of visible diffs. -- **No filler.** Ban list: "Great question", "As mentioned above", "I hope this helps", "Let me know - if you have questions", "Happy to help". -- **No obvious narration.** Do not explain what self-explanatory code does. -- **PR descriptions: what changed and why.** Nothing else. -- **One question at a time.** No shotgun lists of open-ended questions. - -### Context - -- **Re-read the entire thread** before every comment and every push. No exceptions. -- **After a context gap**, reload the full thread (GitHub UI, `gh issue view ` / `gh pr view `, or `curl "https://api.github.com/repos/mllam/neural-lam/issues/"`) before acting. -- **Never repeat** a question already answered or an approach already rejected in the thread. - -### Commits - -- Imperative form, matching existing `git log` style. -- One concern per PR. No unrelated changes. -- AI attribution of tool names is mandatory if used and should be mentioned in the commit message trailer as `Co-authored-by ` - -### Changelog - -Every PR must add a line to `CHANGELOG.md` in the section matching the change type (`Added` / `Changed` / `Fixed` / `Maintenance`). -`maintenance`). +1. **Follow Contributing Guide.** AI agents must adhere to the rules in [CONTRIBUTING.md](docs/contributing/contributing.md) (Issues, PRs, Communication style). +2. **AI Attribution.** Mandatory `Co-authored-by ` in commit trailers when AI tools are used. +3. **Context Gap.** Reload the full thread (GitHub UI or `gh` CLI) after a context gap before acting. +4. **No Placeholders.** Do not use placeholders in code or documentation. diff --git a/CHANGELOG.md b/CHANGELOG.md index fca43415b..446809c1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Split `AGENTS.md` into a technical overview for AI agents and a comprehensive human-facing contributing guide in `docs/contributing/contributing.md` ([#516](https://github.com/mllam/neural-lam/issues/516)) @[yourusername] - Replace remaining `print()` calls with `loguru` `logger.info()` in `compute_standardization_stats.py` for structured and consistent logging @[yourusername] - Change the default ensemble-loading behavior in `WeatherDataset` / `WeatherDataModule` to use all ensemble members as independent samples for ensemble datastores (with matching ensemble-member selection for forcing when available); single-member behavior now requires explicitly opting in via `--load_single_member` [\#332](https://github.com/mllam/neural-lam/pull/332) @kshirajahere - Refactor graph loading: move zero-indexing out of the model and update plotting to prepare using the research-branch graph I/O [\#184](https://github.com/mllam/neural-lam/pull/184) @zweihuehner diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..414a9d611 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,48 @@ +# Contributing Guidelines + +Mandatory rules for contributing to Neural-LAM. Follow these guidelines to ensure your Pull Requests are accepted. + +--- + +## Issues + +1. **Search before creating.** Use any of: GitHub UI search, `gh issue list --state all --search ""`, or `curl "https://api.github.com/search/issues?q=+repo:mllam/neural-lam+type:issue"`. Duplicate issues will be closed. +2. **Every PR requires an issue.** No exceptions. Open one first if none exists. +3. **Include minimal example.** Each issue should include a minimal, reproducible example on how to easily recreate a bug, including all necessary module imports and data. Include full traceback if it is a bug-report. + +## Pull Requests + +1. **Search before creating.** Use any of: GitHub UI search, `gh pr list --state all --search ""`, or `curl "https://api.github.com/search/issues?q=+repo:mllam/neural-lam+type:pr"`. If a PR exists for the same issue, contribute there. +2. **Link the issue.** PR body must contain `closes #` or `refs #`. Unlinked PRs will be + rejected. +3. **Use the PR template.** Fill in every section of `.github/pull_request_template.md`. Do not + delete or skip sections. +4. **Read the full issue thread before writing code.** Rejected approaches and prior decisions are + there. Ignoring them wastes everyone's time. +5. **Run pre-commit hooks locally.** Linting needs to be done locally before each new commit with e.g. `uvx pre-commit run --all` +6. **Testing Mandate.** Run `pytests tests/` before opening a PR and if tests fail do not open the PR , fix the failure first. + +## Communication + +- **Terse.** One sentence per point. No preamble. No summaries of visible diffs. +- **No filler.** Ban list: "Great question", "As mentioned above", "I hope this helps", "Let me know + if you have questions", "Happy to help". +- **No obvious narration.** Do not explain what self-explanatory code does. +- **PR descriptions: what changed and why.** Nothing else. +- **One question at a time.** No shotgun lists of open-ended questions. + +## Context + +- **Re-read the entire thread** before every comment and every push. No exceptions. +- **After a context gap**, reload the full thread (GitHub UI, `gh issue view ` / `gh pr view `, or `curl "https://api.github.com/repos/mllam/neural-lam/issues/"`) before acting. +- **Never repeat** a question already answered or an approach already rejected in the thread. + +## Commits & Changelog + +- **Commit Format.** Imperative form, matching existing `git log` style. +- **One Concern per PR.** No unrelated changes. +- **AI Attribution.** Mandatory `Co-authored-by ` in commit trailers if AI tools are used. +- **CHANGELOG.** Every PR must add a line to `CHANGELOG.md` in the section matching the change type (`Added` / `Changed` / `Fixed` / `Maintenance`). + +--- +*For a technical overview intended for AI agents, see [AGENTS.md](AGENTS.md).* From df85c055e7ac2e8ee9027ce708969d3517ee637d Mon Sep 17 00:00:00 2001 From: codedbyasim Date: Sat, 28 Mar 2026 20:48:04 +0500 Subject: [PATCH 3/3] refactor: split AGENTS.md into human-facing CONTRIBUTING.md and technical AGENTS.md overview --- .../compute_standardization_stats.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/neural_lam/datastore/npyfilesmeps/compute_standardization_stats.py b/neural_lam/datastore/npyfilesmeps/compute_standardization_stats.py index 97bd3cb7b..d4b7e1ee6 100644 --- a/neural_lam/datastore/npyfilesmeps/compute_standardization_stats.py +++ b/neural_lam/datastore/npyfilesmeps/compute_standardization_stats.py @@ -8,7 +8,6 @@ # Third-party import torch import torch.distributed as dist -from loguru import logger from torch.utils.data.distributed import DistributedSampler from tqdm import tqdm @@ -79,10 +78,10 @@ def setup(rank, world_size): # pylint: disable=redefined-outer-name ) master_node = hostname_lines[0].strip() else: - logger.warning( - "Careful, you are running this script with --distributed " + print( + "\033[91mCareful, you are running this script with --distributed " "without any scheduler. In most cases this will result in slower " - "execution and the --distributed flag should be removed." + "execution and the --distributed flag should be removed.\033[0m" ) master_node = "localhost" os.environ["MASTER_ADDR"] = master_node @@ -93,7 +92,7 @@ def setup(rank, world_size): # pylint: disable=redefined-outer-name world_size=world_size, ) if rank == 0: - logger.info( + print( f"Initialized {dist.get_backend()} " f"process group with world size {world_size}." ) @@ -111,7 +110,7 @@ def save_stats( mean = torch.mean(means, dim=0) # (d_features,) second_moment = torch.mean(squares, dim=0) # (d_features,) std = torch.sqrt(second_moment - mean**2) # (d_features,) - logger.info( + print( f"Saving {filename_prefix} mean and std.-dev. to " f"{filename_prefix}_mean.pt and {filename_prefix}_std.pt" ) @@ -133,7 +132,7 @@ def save_stats( flux_mean = torch.mean(flux_means) # (,) flux_second_moment = torch.mean(flux_squares) # (,) flux_std = torch.sqrt(flux_second_moment - flux_mean**2) # (,) - logger.info("Saving flux mean and std.-dev. to flux_stats.pt") + print("Saving flux mean and std.-dev. to flux_stats.pt") torch.save( torch.stack((flux_mean, flux_std)).cpu(), os.path.join(static_dir_path, "flux_stats.pt"), @@ -207,7 +206,7 @@ def main( ) if rank == 0: - logger.info("Computing mean and std.-dev. for parameters...") + print("Computing mean and std.-dev. for parameters...") means, squares, flux_means, flux_squares = [], [], [], [] for init_batch, target_batch, forcing_batch, _ in tqdm(loader): @@ -281,7 +280,7 @@ def main( dist.barrier() if rank == 0: - logger.info("Computing mean and std.-dev. for one-step differences...") + print("Computing mean and std.-dev. for one-step differences...") ds_standard = WeatherDataset( datastore=datastore, split="train", @@ -425,4 +424,4 @@ def cli(): if __name__ == "__main__": - cli() + cli() \ No newline at end of file