From 3ccc50684bd9495ce1b5c9f17b94260c742bb614 Mon Sep 17 00:00:00 2001 From: Sankalp Chudmunge Date: Mon, 28 Sep 2026 15:17:01 +0530 Subject: [PATCH 1/7] docs: update badges and repository urls from mathLab to PINA-org (#834) Fixes #831 --- README.md | 14 +++++++------- pyproject.toml | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 2c1ec00f7..7ab06de48 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ SPDX-License-Identifier: Apache-2.0 PyPI downloads -
+
@@ -154,7 +154,7 @@ To install additional packages required for development, tests, docs, or tutoria

Getting started with PINA

       - +      @@ -169,19 +169,19 @@ Solving a differential problem in PINA follows a clean four-step pipeline
  1. Define the problem and constraints using the - Problem API. + Problem API.
  2. Design your model using PyTorch, PyTorch Geometric, or import from the - Model API. + Model API.
  3. Select or build a Solver using the - Solver API. + Solver API.
  4. Train with the - Trainer API, + Trainer API, powered by PyTorch Lightning.
@@ -368,7 +368,7 @@ If you would like to contribute, please read the

- Contributors diff --git a/pyproject.toml b/pyproject.toml index c15169843..0b0c276e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,8 +47,8 @@ tutorial = [ ] [project.urls] -Homepage = "https://mathlab.github.io/PINA/" -Repository = "https://github.com/mathLab/PINA" +Homepage = "https://pina-org.github.io/PINA/" +Repository = "https://github.com/PINA-org/PINA" [build-system] requires = [ "setuptools>=41", "wheel", "setuptools-git-versioning>=2.0,<3", ] From ab0faf232a20a4429717819308416ab890d9003b Mon Sep 17 00:00:00 2001 From: GiovanniCanali Date: Tue, 29 Sep 2026 11:35:36 +0200 Subject: [PATCH 2/7] update all references to PINA-org --- .github/CODEOWNERS | 44 +++++++++---------- .github/PULL_REQUEST_TEMPLATE.md | 2 +- .github/workflows/monthly-tagger.yml | 4 +- API_scheme.md | 2 +- CHARTER.md | 12 ++--- CONTRIBUTING.md | 4 +- GOVERNANCE.md | 2 +- MAINTAINERS.md | 3 +- SECURITY.md | 2 +- STEERING-COMMITTEE.md | 3 +- docs/source/_contributing.rst | 4 +- docs/source/_installation.rst | 2 +- docs/source/_team.rst | 2 +- docs/source/_templates/layout.html | 2 +- docs/source/conf.py | 2 +- docs/source/index.rst | 2 +- joss/paper.md | 4 +- .../problem/zoo/inverse_poisson_problem.py | 4 +- ...thlab_versioning.py => pina_versioning.py} | 0 19 files changed, 49 insertions(+), 51 deletions(-) rename utils/{mathlab_versioning.py => pina_versioning.py} (100%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2cbbcf345..8d8b19b63 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,34 +2,34 @@ # The default owners for everything in the repo # (Pull requests touching any file in "/" will require review from at least one of these) -* @mathLab/pina-developers -pina/ @mathLab/pina-developers -readme/ @mathLab/pina-developers -tests/ @mathLab/pina-developers -tutorials/ @mathLab/pina-developers -pyproject.toml @mathLab/pina-developers @ndem0 +* @PINA-org/pina-maintainers +pina/ @PINA-org/pina-maintainers +readme/ @PINA-org/pina-maintainers +tests/ @PINA-org/pina-maintainers +tutorials/ @PINA-org/pina-maintainers +pyproject.toml @PINA-org/pina-committee @ndem0 # Owners for documentation -docs/ @mathLab/pina-developers @dario-coscia +docs/ @PINA-org/pina-maintainers # Owners for JOSS joss/ @ndem0 @annaivagnes @dario-coscia # Owners for project-wide config (GitHub workflows, formatting, etc.) -.github/ @ndem0 @dario-coscia -.gitattributes @ndem0 @dario-coscia -.gitignore @ndem0 @dario-coscia +.github/ @PINA-org/pina-committee +.gitattributes @PINA-org/pina-committee +.gitignore @PINA-org/pina-committee # Security & policy files -CITATION.cff @FilippoOlivo @GiovanniCanali @ndem0 @dario-coscia -CONTRIBUTING.md @FilippoOlivo @GiovanniCanali @ndem0 @dario-coscia -LICENSE.rst @FilippoOlivo @GiovanniCanali @ndem0 @dario-coscia -SECURITY.md @FilippoOlivo @GiovanniCanali @ndem0 @dario-coscia -CODE_OF_CONDUCT.md @FilippoOlivo @GiovanniCanali @ndem0 @dario-coscia -MAINTAINERS.md @FilippoOlivo @GiovanniCanali @ndem0 @dario-coscia -ANTITRUST.md @FilippoOlivo @GiovanniCanali @ndem0 @dario-coscia -CHARTER.md @FilippoOlivo @GiovanniCanali @ndem0 @dario-coscia -GOVERNANCE.md @FilippoOlivo @GiovanniCanali @ndem0 @dario-coscia -STEERING-COMMITTEE.md @FilippoOlivo @GiovanniCanali @ndem0 @dario-coscia -TRADEMARKS.md @FilippoOlivo @GiovanniCanali @ndem0 @dario-coscia -utils @FilippoOlivo @GiovanniCanali @ndem0 @dario-coscia +CITATION.cff @PINA-org/pina-committee +CONTRIBUTING.md @PINA-org/pina-committee +LICENSE.rst @PINA-org/pina-committee +SECURITY.md @PINA-org/pina-committee +CODE_OF_CONDUCT.md @PINA-org/pina-committee +MAINTAINERS.md @PINA-org/pina-committee +ANTITRUST.md @PINA-org/pina-committee +CHARTER.md @PINA-org/pina-committee +GOVERNANCE.md @PINA-org/pina-committee +STEERING-COMMITTEE.md @PINA-org/pina-committee +TRADEMARKS.md @PINA-org/pina-committee +utils @PINA-org/pina-committee diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 100235776..8e43e31dc 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -6,7 +6,7 @@ This PR fixes #ISSUE_NUMBER. ## Checklist -- [ ] Code follows the project’s [Code Style Guidelines](https://github.com/mathLab/PINA/blob/master/CONTRIBUTING.md#code-style--guidelines) +- [ ] Code follows the project’s [Code Style Guidelines](https://github.com/PINA-org/PINA/blob/master/CONTRIBUTING.md#code-style--guidelines) - [ ] Tests have been added or updated - [ ] Documentation has been updated if necessary - [ ] Pull request is linked to an open issue diff --git a/.github/workflows/monthly-tagger.yml b/.github/workflows/monthly-tagger.yml index ef7a7d902..2cbfccf34 100644 --- a/.github/workflows/monthly-tagger.yml +++ b/.github/workflows/monthly-tagger.yml @@ -36,8 +36,8 @@ jobs: - name: Create and push the tag run: | - python utils/mathlab_versioning.py set --only-date "post$(date +%y%m)" - VERS=$(python utils/mathlab_versioning.py get) + python utils/pina_versioning.py set --only-date "post$(date +%y%m)" + VERS=$(python utils/pina_versioning.py get) git config --global user.name 'Monthly Tag bot' git config --global user.email 'mtbot@noreply.github.com' git add pyproject.toml diff --git a/API_scheme.md b/API_scheme.md index 800a04741..64ce6e4c7 100644 --- a/API_scheme.md +++ b/API_scheme.md @@ -2,7 +2,7 @@ Here is a high-level overview of PINA’s main modules. For full details, refer to the -documentation. +documentation. ```mermaid flowchart TB diff --git a/CHARTER.md b/CHARTER.md index 6a03b9605..e871ede6e 100644 --- a/CHARTER.md +++ b/CHARTER.md @@ -1,6 +1,6 @@ # Charter for the PINA Organization -This is the organizational charter for the PINA Organization. In this Charter and related documents, “PINA Organization” means the entity designated in this Charter as the governing body of the PINA project. At the time of writing, this is the PINA Steering Committee. If governance changes in the future, references to “PINA Organization” automatically refer to the successor entity named here without rewriting other policies. By adding their name to the [Steering Committee.md file](https://github.com/mathLab/PINA/blob/master/STEERING-COMMITTEE.md), Steering Committee members agree as follows. +This is the organizational charter for the PINA Organization. In this Charter and related documents, “PINA Organization” means the entity designated in this Charter as the governing body of the PINA project. At the time of writing, this is the PINA Steering Committee. If governance changes in the future, references to “PINA Organization” automatically refer to the successor entity named here without rewriting other policies. By adding their name to the [Steering Committee.md file](https://github.com/PINA-org/PINA/blob/master/STEERING-COMMITTEE.md), Steering Committee members agree as follows. ## 1. Mission @@ -19,7 +19,7 @@ By pursuing these goals, the Organization aims to be a cornerstone resource in c **2.1 Purpose**. The Steering Committee will be responsible for all technical oversight, project approval and oversight, policy oversight, and trademark management. -**2.2 Composition**. The Steering Committee voting members are listed in the [STEERING-COMMITEE.md](https://github.com/mathLab/PINA/blob/master/STEERING-COMMITTEE.md) file in the repository. +**2.2 Composition**. The Steering Committee voting members are listed in the [STEERING-COMMITEE.md](https://github.com/PINA-org/PINA/blob/master/STEERING-COMMITTEE.md) file in the repository. Voting members may be added or removed by no less than 75% affirmative vote of the Steering Committee. The Steering Committee will appoint a Chair responsible for organizing Steering Committee activity. @@ -39,11 +39,11 @@ In addition to the method set out in section 2.2, the membership of a Steering C ## 5. Trademarks -Any names, trademarks, service marks, logos, mascots, or similar indicators of source or origin and the goodwill associated with them arising out of the PINA's activities or PINA projects' activities (the "Marks"), are controlled by the PINA Organization. PINA Marks may be only used in accordance with the [trademark policy](https://github.com/mathLab/PINA/blob/master/TRADEMARKS.md). +Any names, trademarks, service marks, logos, mascots, or similar indicators of source or origin and the goodwill associated with them arising out of the PINA's activities or PINA projects' activities (the "Marks"), are controlled by the PINA Organization. PINA Marks may be only used in accordance with the [trademark policy](https://github.com/PINA-org/PINA/blob/master/TRADEMARKS.md). ## 6. Antitrust Policy -The Steering Committee is bound by the [antitrust policy](https://github.com/mathLab/PINA/blob/master/ANTITRUST.md). +The Steering Committee is bound by the [antitrust policy](https://github.com/PINA-org/PINA/blob/master/ANTITRUST.md). ## 7. No Confidentiality @@ -59,11 +59,11 @@ In order to be eligible to be a PINA project, a project must: - For code, a license on the Open Source Initiative's list of [Popular Licenses](https://opensource.org/licenses). - For data, a license on the Open Knowledge Foundation's list of [Recommended Conformant Licenses](http://opendefinition.org/licenses/). - For specifications, a community developed and maintained specification agreement, such the [Open Web Foundation Agreements](https://www.openwebfoundation.org/the-agreements) or [Community Specification Agreement](https://github.com/CommunitySpecification/1.0). -* Include and adhere to the PINA's policies, including the [trademark policy](https://github.com/mathLab/PINA/blob/master/TRADEMARKS.md), the [antitrust policy](https://github.com/mathLab/PINA/blob/master/ANTITRUST.md), and the [code of conduct](https://github.com/mathLab/PINA/blob/master/CODE_OF_CONDUCT.md). +* Include and adhere to the PINA's policies, including the [trademark policy](https://github.com/PINA-org/PINA/blob/master/TRADEMARKS.md), the [antitrust policy](https://github.com/PINA-org/PINA/blob/master/ANTITRUST.md), and the [code of conduct](https://github.com/PINA-org/PINA/blob/master/CODE_OF_CONDUCT.md). ## 9. Amendments -Amendments to this charter, the [antitrust policy](https://github.com/mathLab/PINA/blob/master/ANTITRUST.md), the [trademark policy](https://github.com/mathLab/PINA/blob/master/TRADEMARKS.md), or the [code of conduct](https://github.com/mathLab/PINA/blob/master/CODE_OF_CONDUCT.md) may only be made with at least a 75% affirmative vote of the Steering Committee. +Amendments to this charter, the [antitrust policy](https://github.com/PINA-org/PINA/blob/master/ANTITRUST.md), the [trademark policy](https://github.com/PINA-org/PINA/blob/master/TRADEMARKS.md), or the [code of conduct](https://github.com/PINA-org/PINA/blob/master/CODE_OF_CONDUCT.md) may only be made with at least a 75% affirmative vote of the Steering Committee. --- ## Attribution diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3bde485db..4532aad53 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,7 +29,7 @@ We encourage all contributions, big or small! ## Reporting Bugs -If you find a bug, please open an [issue](https://github.com/mathLab/PINA/issues) and include: +If you find a bug, please open an [issue](https://github.com/PINA-org/PINA/issues) and include: - A clear and descriptive title - Steps to reproduce the problem - What you expected to happen @@ -42,7 +42,7 @@ If you find a bug, please open an [issue](https://github.com/mathLab/PINA/issues ## Suggesting Enhancements We welcome new ideas! If you have an idea to improve PINA: -1. Check the [issue tracker](https://github.com/mathLab/PINA/issues) or the [discussions](https://github.com/mathLab/PINA/discussions) to see if someone has already suggested it. +1. Check the [issue tracker](https://github.com/PINA-org/PINA/issues) or the [discussions](https://github.com/PINA-org/PINA/discussions) to see if someone has already suggested it. 2. If not, open a new issue describing: - The enhancement you'd like - Why it would be useful diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 63ffc753a..6890a18b0 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -1,6 +1,6 @@ # Governance Policy -This document provides the governance policy for the PINA. Maintainers agree to this policy and to abide by all PINA polices, including the [code of conduct](https://github.com/mathLab/PINA/blob/master/CODE_OF_CONDUCT.md), [trademark policy](https://github.com/mathLab/PINA/blob/master/TRADEMARKS.md), and [antitrust policy](https://github.com/mathLab/PINA/blob/master/ANTITRUST.md) by adding their name to the [maintainers.md file](https://github.com/mathLab/PINA/blob/master/MAINTAINERS.md). +This document provides the governance policy for the PINA. Maintainers agree to this policy and to abide by all PINA polices, including the [code of conduct](https://github.com/PINA-org/PINA/blob/master/CODE_OF_CONDUCT.md), [trademark policy](https://github.com/PINA-org/PINA/blob/master/TRADEMARKS.md), and [antitrust policy](https://github.com/PINA-org/PINA/blob/master/ANTITRUST.md) by adding their name to the [maintainers.md file](https://github.com/PINA-org/PINA/blob/master/MAINTAINERS.md). ## 1. Roles. diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 143706f80..34b988ee8 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -2,7 +2,7 @@ # Maintainers -This document lists the Maintainers of the Project. Maintainers may be added once approved by the existing maintainers as described in the [Governance document](https://github.com/mathLab/PINA/blob/master/GOVERNANCE.md). By adding your name to this list you are agreeing to abide by the Project governance documents and to abide by all of the Organization's polices, including the [code of conduct](https://github.com/mathLab/PINA/blob/master/CODE_OF_CONDUCT.md), [trademark policy](https://github.com/mathLab/PINA/blob/master/TRADEMARKS.md), and [antitrust policy](https://github.com/mathLab/PINA/blob/master/ANTITRUST.md). If you are participating because of your affiliation with another organization (designated below), you represent that you have the authority to bind that organization to these policies. +This document lists the Maintainers of the Project. Maintainers may be added once approved by the existing maintainers as described in the [Governance document](https://github.com/PINA-org/PINA/blob/master/GOVERNANCE.md). By adding your name to this list you are agreeing to abide by the Project governance documents and to abide by all of the Organization's polices, including the [code of conduct](https://github.com/PINA-org/PINA/blob/master/CODE_OF_CONDUCT.md), [trademark policy](https://github.com/PINA-org/PINA/blob/master/TRADEMARKS.md), and [antitrust policy](https://github.com/PINA-org/PINA/blob/master/ANTITRUST.md). If you are participating because of your affiliation with another organization (designated below), you represent that you have the authority to bind that organization to these policies. | **GithubID** | **Email Address** | **Organization** | @@ -12,7 +12,6 @@ This document lists the Maintainers of the Project. Maintainers may be added onc | @ndem0 | demo.nicola@gmail.com | SISSA - FAST COMPUTING SRL | | @AleDinve | gdinvern@sissa.it | SISSA | | @annaivagnes | aivagnes@sissa.it | SISSA | -| @FilippoOlivo | filippo@filippoolivo.com | SISSA - FAST COMPUTING SRL | | @guglielmopadula | gpadula@sissa.it | SISSA | | @fpichi | fpichi@sissa.it | SISSA | diff --git a/SECURITY.md b/SECURITY.md index a425740c2..794df5667 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,4 +16,4 @@ Security fixes are given priority and might be enough to cause a new version to ## Reporting a Vulnerability -To ensure vulnerability reports reach the maintainers as quickly as possible, the preferred way is to use the ["Report a vulnerability"](https://github.com/mathLab/PINA/security/advisories/new) button under the "Security" tab of the associated GitHub project. This creates a private communication channel between the reporter and the maintainers. +To ensure vulnerability reports reach the maintainers as quickly as possible, the preferred way is to use the ["Report a vulnerability"](https://github.com/PINA-org/PINA/security/advisories/new) button under the "Security" tab of the associated GitHub project. This creates a private communication channel between the reporter and the maintainers. diff --git a/STEERING-COMMITTEE.md b/STEERING-COMMITTEE.md index b97c3a0b9..156da704d 100644 --- a/STEERING-COMMITTEE.md +++ b/STEERING-COMMITTEE.md @@ -1,13 +1,12 @@ # Steering Committee -This document lists the members of the Organization's Steering Committee (in alphabetical order). Voting members may be added once approved by the Steering Committee as described in the [charter](github.com/mathLab/PINA/blob/master/CHARTER.md). By adding your name to this list you are agreeing to abide by all Organization polices, including the [charter](github.com/mathLab/PINA/blob/master/CHARTER.md), the [code of conduct](https://github.com/mathLab/PINA/blob/master/CODE_OF_CONDUCT.md), the [trademark policy](https://github.com/mathLab/PINA/blob/master/TRADEMARKS.md), and the [antitrust policy](https://github.com/mathLab/PINA/blob/master/ANTITRUST.md). If you are serving on the Steering Committee because of your affiliation with another organization (designated below), you represent that you have authority to bind that organization to these policies. +This document lists the members of the Organization's Steering Committee (in alphabetical order). Voting members may be added once approved by the Steering Committee as described in the [charter](https://github.com/PINA-org/PINA/blob/master/CHARTER.md). By adding your name to this list you are agreeing to abide by all Organization polices, including the [charter](https://github.com/PINA-org/PINA/blob/master/CHARTER.md), the [code of conduct](https://github.com/PINA-org/PINA/blob/master/CODE_OF_CONDUCT.md), the [trademark policy](https://github.com/PINA-org/PINA/blob/master/TRADEMARKS.md), and the [antitrust policy](https://github.com/PINA-org/PINA/blob/master/ANTITRUST.md). If you are serving on the Steering Committee because of your affiliation with another organization (designated below), you represent that you have authority to bind that organization to these policies. | **NAME** | **Handle** | **Affiliated Organization** | | ------------ | ------------ | --------------------------- | | Giovanni Canali | @GiovanniCanali | SISSA | | Dario Coscia | @dario-coscia | SISSA | | Nicola Demo | @ndem0 | SISSA - FAST COMPUTING SRL | -| Filippo Olivo | @FilippoOlivo | SISSA - FAST COMPUTING SRL | --- ## Attribution diff --git a/docs/source/_contributing.rst b/docs/source/_contributing.rst index b981f6ba7..ea2073534 100644 --- a/docs/source/_contributing.rst +++ b/docs/source/_contributing.rst @@ -22,7 +22,7 @@ We encourage all contributions, big or small! Reporting Bugs -------------- -If you find a bug, please open an `issue `_ and include: +If you find a bug, please open an `issue `_ and include: - A clear and descriptive title - Steps to reproduce the problem @@ -36,7 +36,7 @@ Suggesting Enhancements We welcome new ideas! If you have an idea to improve PINA: -1. Check the `issue tracker `_ or the `discussions `_ to see if someone has already suggested it. +1. Check the `issue tracker `_ or the `discussions `_ to see if someone has already suggested it. 2. If not, open a new issue describing: - The enhancement you would like - Why it would be useful diff --git a/docs/source/_installation.rst b/docs/source/_installation.rst index a0bca26f5..1e4eb3541 100644 --- a/docs/source/_installation.rst +++ b/docs/source/_installation.rst @@ -29,7 +29,7 @@ The official distribution is on GitHub. Clone the repository: .. code-block:: bash - git clone https://github.com/mathLab/PINA + git clone https://github.com/PINA-org/PINA Then install in editable mode: diff --git a/docs/source/_team.rst b/docs/source/_team.rst index f1fc47422..b8abdef58 100644 --- a/docs/source/_team.rst +++ b/docs/source/_team.rst @@ -25,7 +25,7 @@ A significant part of **PINA** has been written either as a by-product of funded :align: center :width: 500 -We also acknowledge the contribution of `Maria Strazzullo `_ in the early development of the package. A special thank you goes to all the students and researchers from different universities who contributed to the package. Finally, we warmly thank all the `contributors `_ who are the real heart of **PINA**! +We also acknowledge the contribution of `Maria Strazzullo `_ in the early development of the package. A special thank you goes to all the students and researchers from different universities who contributed to the package. Finally, we warmly thank all the `contributors `_ who are the real heart of **PINA**! .. figure:: index_files/university_dev_pina.png :align: center diff --git a/docs/source/_templates/layout.html b/docs/source/_templates/layout.html index c1bc42107..7c0e1c383 100644 --- a/docs/source/_templates/layout.html +++ b/docs/source/_templates/layout.html @@ -6,7 +6,7 @@

{% trans copyright=copyright|e %}© Copyright {{ copyright }}, PINA Developers.{% endtrans %}
+ href="https://github.com/PINA-org/PINA/">PINA Developers.{% endtrans %}
Created using Sphinx and the PyData Theme.

diff --git a/docs/source/conf.py b/docs/source/conf.py index 7f5f4f8c7..9e09f6600 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -127,7 +127,7 @@ "icon_links": [ { "name": "GitHub", - "url": "https://github.com/mathLab/PINA", + "url": "https://github.com/PINA-org/PINA", "icon": "fab fa-github", "type": "fontawesome", }, diff --git a/docs/source/index.rst b/docs/source/index.rst index 924a7fdbf..05ebef503 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -16,7 +16,7 @@ Welcome to PINA's documentation! Get Started Quickstart - View on GitHub + View on GitHub
diff --git a/joss/paper.md b/joss/paper.md index b63d46d43..133266e85 100644 --- a/joss/paper.md +++ b/joss/paper.md @@ -62,8 +62,8 @@ Among all these frameworks, PINA wants to emerge for its easiness of usage, allo Built over PyTorch --- in order to inherit the \verb+autograd+ module and all the other features already implemented --- PINA provides indeed documented API to explain usage and capabilities of the different classes. We have built several abstract interfaces not only for better structure of the source code but especially to give the final user an easy entry point to implement their own extensions, like new loss functions, new training procedures, and so on. This aspect, together with the capability to use all the PyTorch models, makes it possible to incorporate almost any existing architecture into the PINA framework. We have decided to build it on top of PyTorch in order to exploit the \verb+autograd+ module, as well as all the other features implemented in this framework. The final outcome is then a library with incremental complexity, capable of being used by the new users to perform the first investigation using PINNs, but also as a core framework to actively develop new features to improve the discussed methodology. -The high-level structure of the package is depicted in our [API](https://github.com/mathLab/PINA/tree/master/readme/API_color.png); the approximated solution of a differential equation can be implemented using PINA in a few lines of code thanks to the intuitive and user-friendly interface. -Besides the user-friendly interface, PINA also offers several examples and tutorials, aiming to guide new users toward an easy exploration of the software features. The online documentation is released at \url{https://mathlab.github.io/PINA/}, while the robustness of the package is continuously monitored by unit tests. +The high-level structure of the package is depicted in our [API](https://github.com/PINA-org/PINA/tree/master/readme/PINA_API.png); the approximated solution of a differential equation can be implemented using PINA in a few lines of code thanks to the intuitive and user-friendly interface. +Besides the user-friendly interface, PINA also offers several examples and tutorials, aiming to guide new users toward an easy exploration of the software features. The online documentation is released at \url{https://PINA-org.github.io/PINA/}, while the robustness of the package is continuously monitored by unit tests. PINA workflow is characterized by 3 main steps: the problem formulation, the model definition, i.e., the structure of the neural network used, and the training, eventually followed by the data visualization. diff --git a/pina/_src/problem/zoo/inverse_poisson_problem.py b/pina/_src/problem/zoo/inverse_poisson_problem.py index 9a5a8d908..b30b5d596 100644 --- a/pina/_src/problem/zoo/inverse_poisson_problem.py +++ b/pina/_src/problem/zoo/inverse_poisson_problem.py @@ -154,11 +154,11 @@ def __init__(self, load=True, data_size=1.0): # Define URLs for input and output data input_url = ( - "https://github.com/mathLab/PINA/raw/refs/heads/master" + "https://github.com/PINA-org/PINA/raw/refs/heads/master" "/tutorials/tutorial7/data/pts_0.5_0.5" ) output_url = ( - "https://github.com/mathLab/PINA/raw/refs/heads/master" + "https://github.com/PINA-org/PINA/raw/refs/heads/master" "/tutorials/tutorial7/data/pinn_solution_0.5_0.5" ) diff --git a/utils/mathlab_versioning.py b/utils/pina_versioning.py similarity index 100% rename from utils/mathlab_versioning.py rename to utils/pina_versioning.py From 266f964662f466a437887725a6578178cbcca888 Mon Sep 17 00:00:00 2001 From: Sankalp Chudmunge Date: Sun, 4 Oct 2026 02:45:56 +0530 Subject: [PATCH 3/7] feat(label_tensor): add dim parameter to LabelTensor.stack method (#835) --- pina/_src/core/label_tensor.py | 38 ++++- tests/test_label_tensor/test_label_tensor.py | 160 +++++++++++++++++++ 2 files changed, 193 insertions(+), 5 deletions(-) diff --git a/pina/_src/core/label_tensor.py b/pina/_src/core/label_tensor.py index d97ef077d..4aebb7206 100644 --- a/pina/_src/core/label_tensor.py +++ b/pina/_src/core/label_tensor.py @@ -374,24 +374,52 @@ def cat(tensors, dim=0): return cat_tensor @staticmethod - def stack(tensors): + def stack(tensors, dim=0): """ Stacks a list of tensors along a new dimension. For more details, see :meth:`torch.stack`. :param list[LabelTensor] tensors: A list of tensors to stack. All tensors must have the same shape. + :param int dim: Dimension along which to stack the tensors. Default is 0. :return: A new :class:`~pina.label_tensor.LabelTensor` instance obtained by stacking the input tensors. :rtype: LabelTensor """ + if not tensors: + return [] + if len(tensors) == 1: + return tensors[0] + + # In PyTorch, stacking adds a new dimension, so valid dims are - (ndim + 1) <= dim <= ndim + ndim = tensors[0].ndim + if dim < 0: + dim = ndim + 1 + dim + if dim < 0 or dim > ndim: + raise IndexError( + f"Dimension out of range (expected to be in range of [{-(ndim + 1)}, {ndim}], but got {dim})" + ) + + # Check that all tensors have consistent labels + tensors_labels = [tensor.stored_labels for tensor in tensors] + for key in tensors_labels[0]: + if any( + tensors_labels[i].get(key) != tensors_labels[0][key] + for i in range(len(tensors_labels)) + ): + raise RuntimeError("All tensors must have the same labels.") # Perform stacking in torch - new_tensor = torch.stack(tensors) + new_tensor = torch.stack(tensors, dim=dim) + + # Shift label dimension indices at or after `dim` by +1 + labels = {} + for key, value in tensors[0]._labels.items(): + if key >= dim: + labels[key + 1] = value + else: + labels[key] = value - # Increase labels keys by 1 - labels = tensors[0]._labels - labels = {key + 1: value for key, value in labels.items()} new_tensor._labels = labels return new_tensor diff --git a/tests/test_label_tensor/test_label_tensor.py b/tests/test_label_tensor/test_label_tensor.py index ca4ae2f1a..e770fe3a8 100644 --- a/tests/test_label_tensor/test_label_tensor.py +++ b/tests/test_label_tensor/test_label_tensor.py @@ -229,6 +229,166 @@ def test_vstack_2D(): assert lt_stacked.full_labels[1]["name"] == "second" +def test_stack_2D(): + data_1 = torch.rand(20, 3) + labels = {1: {"dof": ["x", "y", "z"], "name": "vars"}} + lt1 = LabelTensor(data_1, labels) + lt2 = LabelTensor(data_1, labels) + + # Test default dim=0 + lt_stacked_0 = LabelTensor.stack([lt1, lt2], dim=0) + assert lt_stacked_0.shape == (2, 20, 3) + assert lt_stacked_0.full_labels[0]["dof"] == range(2) + assert lt_stacked_0.full_labels[0]["name"] == 0 + assert lt_stacked_0.full_labels[1]["dof"] == range(20) + assert lt_stacked_0.full_labels[1]["name"] == 1 + assert lt_stacked_0.full_labels[2]["dof"] == ["x", "y", "z"] + assert lt_stacked_0.full_labels[2]["name"] == "vars" + assert lt_stacked_0.stored_labels == { + 2: {"dof": ["x", "y", "z"], "name": "vars"} + } + assert lt_stacked_0.labels == ["x", "y", "z"] + + # Test dim=1 + lt_stacked_1 = LabelTensor.stack([lt1, lt2], dim=1) + assert lt_stacked_1.shape == (20, 2, 3) + assert lt_stacked_1.full_labels[0]["dof"] == range(20) + assert lt_stacked_1.full_labels[0]["name"] == 0 + assert lt_stacked_1.full_labels[1]["dof"] == range(2) + assert lt_stacked_1.full_labels[1]["name"] == 1 + assert lt_stacked_1.full_labels[2]["dof"] == ["x", "y", "z"] + assert lt_stacked_1.full_labels[2]["name"] == "vars" + assert lt_stacked_1.stored_labels == { + 2: {"dof": ["x", "y", "z"], "name": "vars"} + } + assert lt_stacked_1.labels == ["x", "y", "z"] + + # Test dim=2 and negative dim=-1 + lt_stacked_2 = LabelTensor.stack([lt1, lt2], dim=2) + lt_stacked_neg = LabelTensor.stack([lt1, lt2], dim=-1) + for lt_s in [lt_stacked_2, lt_stacked_neg]: + assert lt_s.shape == (20, 3, 2) + assert lt_s.full_labels[0]["dof"] == range(20) + assert lt_s.full_labels[0]["name"] == 0 + assert lt_s.full_labels[1]["dof"] == ["x", "y", "z"] + assert lt_s.full_labels[1]["name"] == "vars" + assert lt_s.full_labels[2]["dof"] == range(2) + assert lt_s.full_labels[2]["name"] == 2 + assert lt_s.stored_labels == { + 1: {"dof": ["x", "y", "z"], "name": "vars"} + } + assert lt_s.labels is None + + +def test_stack_3D(): + data_1 = torch.rand(20, 3, 2) + labels_1 = { + 1: {"dof": ["a", "b", "c"], "name": "first"}, + 2: {"dof": ["x", "y"], "name": "second"}, + } + lt1 = LabelTensor(data_1, labels_1) + data_2 = torch.rand(20, 3, 2) + lt2 = LabelTensor(data_2, labels_1) + + # Test dim=0 (and dim=-4) + lt_stacked_0 = LabelTensor.stack([lt1, lt2], dim=0) + lt_stacked_neg4 = LabelTensor.stack([lt1, lt2], dim=-4) + for lt_s in [lt_stacked_0, lt_stacked_neg4]: + assert lt_s.shape == (2, 20, 3, 2) + assert lt_s.full_labels[0]["dof"] == range(2) + assert lt_s.full_labels[0]["name"] == 0 + assert lt_s.full_labels[1]["dof"] == range(20) + assert lt_s.full_labels[1]["name"] == 1 + assert lt_s.full_labels[2]["dof"] == ["a", "b", "c"] + assert lt_s.full_labels[2]["name"] == "first" + assert lt_s.full_labels[3]["dof"] == ["x", "y"] + assert lt_s.full_labels[3]["name"] == "second" + assert lt_s.stored_labels == { + 2: {"dof": ["a", "b", "c"], "name": "first"}, + 3: {"dof": ["x", "y"], "name": "second"}, + } + assert lt_s.labels == ["x", "y"] + + # Test dim=1 (and dim=-3) + lt_stacked_1 = LabelTensor.stack([lt1, lt2], dim=1) + lt_stacked_neg3 = LabelTensor.stack([lt1, lt2], dim=-3) + for lt_s in [lt_stacked_1, lt_stacked_neg3]: + assert lt_s.shape == (20, 2, 3, 2) + assert lt_s.full_labels[0]["dof"] == range(20) + assert lt_s.full_labels[0]["name"] == 0 + assert lt_s.full_labels[1]["dof"] == range(2) + assert lt_s.full_labels[1]["name"] == 1 + assert lt_s.full_labels[2]["dof"] == ["a", "b", "c"] + assert lt_s.full_labels[2]["name"] == "first" + assert lt_s.full_labels[3]["dof"] == ["x", "y"] + assert lt_s.full_labels[3]["name"] == "second" + assert lt_s.stored_labels == { + 2: {"dof": ["a", "b", "c"], "name": "first"}, + 3: {"dof": ["x", "y"], "name": "second"}, + } + assert lt_s.labels == ["x", "y"] + + # Test dim=2 (and dim=-2) + lt_stacked_2 = LabelTensor.stack([lt1, lt2], dim=2) + lt_stacked_neg2 = LabelTensor.stack([lt1, lt2], dim=-2) + for lt_s in [lt_stacked_2, lt_stacked_neg2]: + assert lt_s.shape == (20, 3, 2, 2) + assert lt_s.full_labels[0]["dof"] == range(20) + assert lt_s.full_labels[0]["name"] == 0 + assert lt_s.full_labels[1]["dof"] == ["a", "b", "c"] + assert lt_s.full_labels[1]["name"] == "first" + assert lt_s.full_labels[2]["dof"] == range(2) + assert lt_s.full_labels[2]["name"] == 2 + assert lt_s.full_labels[3]["dof"] == ["x", "y"] + assert lt_s.full_labels[3]["name"] == "second" + assert lt_s.stored_labels == { + 1: {"dof": ["a", "b", "c"], "name": "first"}, + 3: {"dof": ["x", "y"], "name": "second"}, + } + assert lt_s.labels == ["x", "y"] + + # Test dim=3 (and dim=-1) + lt_stacked_3 = LabelTensor.stack([lt1, lt2], dim=3) + lt_stacked_neg1 = LabelTensor.stack([lt1, lt2], dim=-1) + for lt_s in [lt_stacked_3, lt_stacked_neg1]: + assert lt_s.shape == (20, 3, 2, 2) + assert lt_s.full_labels[0]["dof"] == range(20) + assert lt_s.full_labels[0]["name"] == 0 + assert lt_s.full_labels[1]["dof"] == ["a", "b", "c"] + assert lt_s.full_labels[1]["name"] == "first" + assert lt_s.full_labels[2]["dof"] == ["x", "y"] + assert lt_s.full_labels[2]["name"] == "second" + assert lt_s.full_labels[3]["dof"] == range(2) + assert lt_s.full_labels[3]["name"] == 3 + assert lt_s.stored_labels == { + 1: {"dof": ["a", "b", "c"], "name": "first"}, + 2: {"dof": ["x", "y"], "name": "second"}, + } + assert lt_s.labels is None + + +def test_stack_errors(): + data_1 = torch.rand(20, 3) + lt1 = LabelTensor(data_1, {1: {"dof": ["x", "y", "z"], "name": "vars"}}) + lt2 = LabelTensor(data_1, {1: {"dof": ["a", "b", "c"], "name": "vars"}}) + + # Empty list + assert LabelTensor.stack([]) == [] + + # Single tensor + assert LabelTensor.stack([lt1]) is lt1 + + # Out of range dim + with pytest.raises(IndexError): + LabelTensor.stack([lt1, lt1], dim=3) + with pytest.raises(IndexError): + LabelTensor.stack([lt1, lt1], dim=-4) + + # Inconsistent labels + with pytest.raises(RuntimeError): + LabelTensor.stack([lt1, lt2]) + + def test_sorting(): data = torch.ones(20, 5) data[:, 0] = data[:, 0] * 4 From 34dfb17d9e75ba38b9e5ba3a2e0d9c064dfcda44 Mon Sep 17 00:00:00 2001 From: Dario Coscia Date: Wed, 21 Oct 2026 20:35:31 +0200 Subject: [PATCH 4/7] update --- .claude/hooks/source_edit_guard.py | 78 +++++++++++++++++ .claude/settings.json | 18 ++++ .opencode/commands/pina-agentic.md | 11 ++- .opencode/opencode.json | 11 +++ .opencode/plugin/source-edit-guard.ts | 115 ++++++++++++++++++++++++++ .opencode/skills/RULES.md | 28 +++---- AGENTS.md | 1 - 7 files changed, 237 insertions(+), 25 deletions(-) create mode 100755 .claude/hooks/source_edit_guard.py create mode 100644 .claude/settings.json create mode 100644 .opencode/opencode.json create mode 100644 .opencode/plugin/source-edit-guard.ts diff --git a/.claude/hooks/source_edit_guard.py b/.claude/hooks/source_edit_guard.py new file mode 100755 index 000000000..ff252ac7b --- /dev/null +++ b/.claude/hooks/source_edit_guard.py @@ -0,0 +1,78 @@ +import json +import os +import sys + +PROTECTED_DIRS = ("pina", "tests", "docs") +FILE_KEYS = ("file_path", "filePath", "notebook_path", "notebookPath", "path", "file") + + +def normalize(path): + return path.replace("\\", "/").rstrip("/") + + +def relative_to_project(path, root): + path = normalize(path) + root = normalize(root) + if path.lower().startswith(root.lower() + "/"): + path = path[len(root) + 1 :] + elif path.startswith("/") or (len(path) > 1 and path[1] == ":"): + return None + if path.startswith("./"): + path = path[2:] + return path + + +def is_protected(path, root): + relative = relative_to_project(path, root) + if not relative: + return False + return any(relative == d or relative.startswith(f"{d}/") for d in PROTECTED_DIRS) + + +def input_paths(tool_input): + for key in FILE_KEYS: + value = tool_input.get(key) + if isinstance(value, str): + yield value + elif isinstance(value, list): + for item in value: + if isinstance(item, str): + yield item + + +def main(): + try: + payload = json.load(sys.stdin) + except (json.JSONDecodeError, ValueError): + return 0 + + tool_input = payload.get("tool_input") or {} + if not isinstance(tool_input, dict): + return 0 + + root = os.environ.get("CLAUDE_PROJECT_DIR") or payload.get("cwd") or os.getcwd() + + for path in input_paths(tool_input): + if is_protected(path, root): + relative = relative_to_project(path, root) + print( + json.dumps( + { + "hookSpecificOutput": { + "hookEventName": "PreToolUse", + "permissionDecision": "ask", + "permissionDecisionReason": ( + f"Modifying source file {relative}. " + "Approve this change before continuing." + ), + } + } + ) + ) + return 0 + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 000000000..12b4e3058 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,18 @@ +{ + "hooks": { + "PreToolUse": [ + { + "matcher": "Edit|Write|MultiEdit|NotebookEdit", + "hooks": [ + { + "type": "command", + "command": "python3", + "args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/source_edit_guard.py"], + "timeout": 10, + "statusMessage": "Checking source edit approval..." + } + ] + } + ] + } +} diff --git a/.opencode/commands/pina-agentic.md b/.opencode/commands/pina-agentic.md index 09fc8fe37..0c2874cdb 100644 --- a/.opencode/commands/pina-agentic.md +++ b/.opencode/commands/pina-agentic.md @@ -17,9 +17,9 @@ such as: skill loaded, I'have read the promt and I am ready, etc. **Hard constraints:** - Respect `.opencode/skills/RULES.md`. -- Never write files into the user's project directory. Inline code snippets - in chat are fine; if a file must be written, use a `/tmp/.pina-agent` location - and say so explicitly +- Ask before writing files into the user's project. Inline code snippets are + fine, but confirm the target path first. Anything under `pina/`, `tests/`, or + `docs/` requires explicit user approval before you modify it. - Avoid redundant operator calls. - Don't do broad sweeps of the repo. Targeted API lookups (grep/read a specific file to verify a constructor signature) are fine when the @@ -53,6 +53,5 @@ Guidelines: a session, not a one-shot handoff. - **Close the loop on delivery.** Once the script is finalized (working, sanity-checked, no open questions left), ask the user whether they'd like - it saved to a file and, if so, where — remember this respects the "never - write to the user's project" constraint, so confirm a scratch/output path - rather than assuming one. \ No newline at end of file + it saved to a file and, if so, where. Confirm the path before writing, and + get explicit approval for any source file change. \ No newline at end of file diff --git a/.opencode/opencode.json b/.opencode/opencode.json new file mode 100644 index 000000000..92d34bca7 --- /dev/null +++ b/.opencode/opencode.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://opencode.ai/config.json", + "permission": { + "edit": { + "*": "allow", + "pina/*": "ask", + "tests/*": "ask", + "docs/*": "ask" + } + } +} diff --git a/.opencode/plugin/source-edit-guard.ts b/.opencode/plugin/source-edit-guard.ts new file mode 100644 index 000000000..f495f00af --- /dev/null +++ b/.opencode/plugin/source-edit-guard.ts @@ -0,0 +1,115 @@ +import type { Plugin } from "@opencode-ai/plugin" + +const PROTECTED_DIRS = ["pina", "tests", "docs"] +const EDIT_TOOLS = ["edit", "write", "patch"] + +function toPosix(path: string) { + return path.replace(/\\/g, "/") +} + +function relativeToRoot(path: string, root: string) { + const target = toPosix(path) + const base = toPosix(root).replace(/\/+$/, "") + + if (target === base) return "" + if (target.startsWith(`${base}/`)) return target.slice(base.length + 1) + return target.replace(/^\.\//, "") +} + +function isProtected(path: string, root: string) { + const relative = relativeToRoot(path, root) + return PROTECTED_DIRS.some( + (dir) => relative === dir || relative.startsWith(`${dir}/`), + ) +} + +function collectStrings(value: unknown, result: string[] = []) { + if (typeof value === "string") { + result.push(value) + } else if (Array.isArray(value)) { + for (const item of value) collectStrings(item, result) + } else if (value && typeof value === "object") { + for (const item of Object.values(value)) collectStrings(item, result) + } + return result +} + +function pathsFromToolArgs(args: unknown) { + if (!args || typeof args !== "object") return [] + + const paths: string[] = [] + const record = args as Record + + for (const key of ["filePath", "filepath", "path", "file"]) { + const value = record[key] + if (typeof value === "string") paths.push(value) + } + + if (typeof record.patchText === "string") { + for (const line of record.patchText.split(/\r?\n/)) { + const match = line.match(/^\*\*\* (?:Add|Update|Delete) File: (.+)$/) + if (match) paths.push(match[1].trim()) + } + } + + return paths +} + +function pathsFromPermission(input: { + pattern?: string | string[] + metadata?: Record + title?: string +}) { + const paths = collectStrings(input.pattern) + const metadata = input.metadata ?? {} + + for (const key of ["filePath", "filepath", "path", "file", "files"]) { + if (key in metadata) collectStrings(metadata[key], paths) + } + + if (paths.length === 0 && typeof input.title === "string") { + paths.push(input.title) + } + + return paths +} + +export default (async ({ client, directory, worktree }) => { + const root = worktree || directory + + async function notify(path: string) { + try { + await client.tui.showToast({ + body: { + title: "Source change requires approval", + message: `Approve the permission prompt before modifying ${path}`, + variant: "warning", + duration: 5000, + }, + }) + } catch {} + } + + return { + "permission.ask": async (input, output) => { + if (input.type !== "edit") return + + const paths = pathsFromPermission(input) + if (paths.length === 0) return + + const sourcePath = paths.find((path) => isProtected(path, root)) + if (sourcePath) { + if (output.status !== "deny") output.status = "ask" + await notify(sourcePath) + } + }, + + "tool.execute.before": async (input, output) => { + if (!EDIT_TOOLS.includes(input.tool)) return + + const paths = pathsFromToolArgs(output.args) + const sourcePath = paths.find((path) => isProtected(path, root)) + if (sourcePath) await notify(sourcePath) + }, + } +}) satisfies Plugin diff --git a/.opencode/skills/RULES.md b/.opencode/skills/RULES.md index af04cbd88..4181faa70 100644 --- a/.opencode/skills/RULES.md +++ b/.opencode/skills/RULES.md @@ -2,18 +2,7 @@ These rules apply to **every skill** in this repository. -1. **No source code modification** — Never modify, create, or delete any source - code files (`.py`, `.cpp`, `.js`, `.ts`, `.rs`, etc.) or any files under - `pina/`, `tests/`, `docs/`, or similar source directories. - -2. **Read-only guidance** — Skills exist solely to provide guidance, templates, - and interactive Q&A. Output explanations, code snippets for the user to - copy, and checklists — never write files to the user's project. - -3. **Scope** — If the user asks to edit or write source files, politely decline - and explain that this skill only provides guidance. - -4. **Avoid redundant operator calls in equations** — Differential operators +1. **Avoid redundant operator calls in equations** — Differential operators (`grad`, `div`, `laplacian`, etc.) are **not cached**: every call triggers a new backward pass through the autograd graph. Always compute an operator once for all relevant components and extract what you need, rather than @@ -43,7 +32,7 @@ These rules apply to **every skill** in this repository. This also applies to spatial gradients, divergences, and any other operator that can be computed for all components at once. -5. **Inference goes through the solver, not the raw model** — Always call +2. **Inference goes through the solver, not the raw model** — Always call `solver(input_tensor)` for evaluation at inference time, not `model(input_tensor)` or `solver.model(input_tensor)`. The solver handles label propagation and any post-processing internally. @@ -51,12 +40,12 @@ These rules apply to **every skill** in this repository. specific reason (e.g., multiple models with different forward passes at training vs. inference). -6. **Prefer solver defaults, acknowledge in chat** — Use the default values +3. **Prefer solver defaults, acknowledge in chat** — Use the default values for solver parameters (optimizer, scheduler, loss, weighting, etc.) unless the user explicitly provides different values. Let the user know in chat which defaults are active so they're aware of what's running under the hood. -7. **Use float values in domain fixed-point variables** — +4. **Use float values in domain fixed-point variables** — `CartesianDomain({"t": 0})` or `EllipsoidDomain({"t": 0})` stores the value `0` as a Python `int`, causing `torch.full` to produce an int64 tensor. This later fails when `requires_grad_()` is called (int tensors don't support @@ -74,7 +63,7 @@ These rules apply to **every skill** in this repository. EllipsoidDomain({"t": 0.0}) ``` -8. **Detach LabelTensors before converting to NumPy** — +5. **Detach LabelTensors before converting to NumPy** — A `LabelTensor` with `requires_grad=True` cannot be passed to `matplotlib` or `numpy` directly — PyTorch raises `"Can't call numpy() on Tensor that requires grad"`. Always call @@ -91,12 +80,15 @@ These rules apply to **every skill** in this repository. plt.plot(theta.detach().numpy(), dtheta_dt.detach().numpy()) ``` -9. **Don't call `problem.move_discretisation_into_conditions()` in user scripts** — +6. **Don't call `problem.move_discretisation_into_conditions()` in user scripts** — The Trainer calls this internally before training — the user doesn't need to invoke it manually. Keep user-facing scripts simple: `problem.discretise_domain(...)` per domain and nothing more. -10. **Smoke-Test Training Runs** - Before delivering training code, run a short +7. **Smoke-Test Training Runs** - Before delivering training code, run a short smoke test using only a few epochs to confirm that the pipeline executes successfully and does not fail. After the test passes, restore the final configuration to the intended number of training epochs. + +8. **Modify files** - If the request will modify source files (`pina`, `tests`), + announce which files and wait for the user's explicit approval before editing. \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 5ac1762de..963d5c637 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -75,5 +75,4 @@ ruff check . # lint ## Rules -- Never modify source code (`pina/`, `tests/`, `docs/`). Skills are read-only guidance. - Stay conversational — walk through the workflow naturally. From 6aa6931cd4368c28bbdd8c6272293315e0b3c0dc Mon Sep 17 00:00:00 2001 From: GiovanniCanali Date: Mon, 26 Oct 2026 10:46:21 +0100 Subject: [PATCH 5/7] update agentic rules --- .claude/hooks/source_edit_guard.py | 78 ----------------- .claude/settings.json | 25 +++--- .opencode/opencode.json | 33 ++++++-- .opencode/plugin/source-edit-guard.ts | 115 -------------------------- 4 files changed, 37 insertions(+), 214 deletions(-) delete mode 100755 .claude/hooks/source_edit_guard.py delete mode 100644 .opencode/plugin/source-edit-guard.ts diff --git a/.claude/hooks/source_edit_guard.py b/.claude/hooks/source_edit_guard.py deleted file mode 100755 index ff252ac7b..000000000 --- a/.claude/hooks/source_edit_guard.py +++ /dev/null @@ -1,78 +0,0 @@ -import json -import os -import sys - -PROTECTED_DIRS = ("pina", "tests", "docs") -FILE_KEYS = ("file_path", "filePath", "notebook_path", "notebookPath", "path", "file") - - -def normalize(path): - return path.replace("\\", "/").rstrip("/") - - -def relative_to_project(path, root): - path = normalize(path) - root = normalize(root) - if path.lower().startswith(root.lower() + "/"): - path = path[len(root) + 1 :] - elif path.startswith("/") or (len(path) > 1 and path[1] == ":"): - return None - if path.startswith("./"): - path = path[2:] - return path - - -def is_protected(path, root): - relative = relative_to_project(path, root) - if not relative: - return False - return any(relative == d or relative.startswith(f"{d}/") for d in PROTECTED_DIRS) - - -def input_paths(tool_input): - for key in FILE_KEYS: - value = tool_input.get(key) - if isinstance(value, str): - yield value - elif isinstance(value, list): - for item in value: - if isinstance(item, str): - yield item - - -def main(): - try: - payload = json.load(sys.stdin) - except (json.JSONDecodeError, ValueError): - return 0 - - tool_input = payload.get("tool_input") or {} - if not isinstance(tool_input, dict): - return 0 - - root = os.environ.get("CLAUDE_PROJECT_DIR") or payload.get("cwd") or os.getcwd() - - for path in input_paths(tool_input): - if is_protected(path, root): - relative = relative_to_project(path, root) - print( - json.dumps( - { - "hookSpecificOutput": { - "hookEventName": "PreToolUse", - "permissionDecision": "ask", - "permissionDecisionReason": ( - f"Modifying source file {relative}. " - "Approve this change before continuing." - ), - } - } - ) - ) - return 0 - - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/.claude/settings.json b/.claude/settings.json index 12b4e3058..30747e9e2 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -1,18 +1,15 @@ { - "hooks": { - "PreToolUse": [ - { - "matcher": "Edit|Write|MultiEdit|NotebookEdit", - "hooks": [ - { - "type": "command", - "command": "python3", - "args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/source_edit_guard.py"], - "timeout": 10, - "statusMessage": "Checking source edit approval..." - } - ] - } + "$schema": "https://json.schemastore.org/claude-code-settings.json", + "permissions": { + "defaultMode": "default", + "allow": [ + "Edit" + ], + "ask": [ + "Edit(/pina/**)", + "Edit(/tests/**)", + "Edit(/docs/**)", + "Bash" ] } } diff --git a/.opencode/opencode.json b/.opencode/opencode.json index 92d34bca7..1510be3c8 100644 --- a/.opencode/opencode.json +++ b/.opencode/opencode.json @@ -1,11 +1,30 @@ { "$schema": "https://opencode.ai/config.json", - "permission": { - "edit": { - "*": "allow", - "pina/*": "ask", - "tests/*": "ask", - "docs/*": "ask" + "permissions": [ + { + "action": "edit", + "resource": "*", + "effect": "allow" + }, + { + "action": "edit", + "resource": "pina/*", + "effect": "ask" + }, + { + "action": "edit", + "resource": "tests/*", + "effect": "ask" + }, + { + "action": "edit", + "resource": "docs/*", + "effect": "ask" + }, + { + "action": "shell", + "resource": "*", + "effect": "ask" } - } + ] } diff --git a/.opencode/plugin/source-edit-guard.ts b/.opencode/plugin/source-edit-guard.ts deleted file mode 100644 index f495f00af..000000000 --- a/.opencode/plugin/source-edit-guard.ts +++ /dev/null @@ -1,115 +0,0 @@ -import type { Plugin } from "@opencode-ai/plugin" - -const PROTECTED_DIRS = ["pina", "tests", "docs"] -const EDIT_TOOLS = ["edit", "write", "patch"] - -function toPosix(path: string) { - return path.replace(/\\/g, "/") -} - -function relativeToRoot(path: string, root: string) { - const target = toPosix(path) - const base = toPosix(root).replace(/\/+$/, "") - - if (target === base) return "" - if (target.startsWith(`${base}/`)) return target.slice(base.length + 1) - return target.replace(/^\.\//, "") -} - -function isProtected(path: string, root: string) { - const relative = relativeToRoot(path, root) - return PROTECTED_DIRS.some( - (dir) => relative === dir || relative.startsWith(`${dir}/`), - ) -} - -function collectStrings(value: unknown, result: string[] = []) { - if (typeof value === "string") { - result.push(value) - } else if (Array.isArray(value)) { - for (const item of value) collectStrings(item, result) - } else if (value && typeof value === "object") { - for (const item of Object.values(value)) collectStrings(item, result) - } - return result -} - -function pathsFromToolArgs(args: unknown) { - if (!args || typeof args !== "object") return [] - - const paths: string[] = [] - const record = args as Record - - for (const key of ["filePath", "filepath", "path", "file"]) { - const value = record[key] - if (typeof value === "string") paths.push(value) - } - - if (typeof record.patchText === "string") { - for (const line of record.patchText.split(/\r?\n/)) { - const match = line.match(/^\*\*\* (?:Add|Update|Delete) File: (.+)$/) - if (match) paths.push(match[1].trim()) - } - } - - return paths -} - -function pathsFromPermission(input: { - pattern?: string | string[] - metadata?: Record - title?: string -}) { - const paths = collectStrings(input.pattern) - const metadata = input.metadata ?? {} - - for (const key of ["filePath", "filepath", "path", "file", "files"]) { - if (key in metadata) collectStrings(metadata[key], paths) - } - - if (paths.length === 0 && typeof input.title === "string") { - paths.push(input.title) - } - - return paths -} - -export default (async ({ client, directory, worktree }) => { - const root = worktree || directory - - async function notify(path: string) { - try { - await client.tui.showToast({ - body: { - title: "Source change requires approval", - message: `Approve the permission prompt before modifying ${path}`, - variant: "warning", - duration: 5000, - }, - }) - } catch {} - } - - return { - "permission.ask": async (input, output) => { - if (input.type !== "edit") return - - const paths = pathsFromPermission(input) - if (paths.length === 0) return - - const sourcePath = paths.find((path) => isProtected(path, root)) - if (sourcePath) { - if (output.status !== "deny") output.status = "ask" - await notify(sourcePath) - } - }, - - "tool.execute.before": async (input, output) => { - if (!EDIT_TOOLS.includes(input.tool)) return - - const paths = pathsFromToolArgs(output.args) - const sourcePath = paths.find((path) => isProtected(path, root)) - if (sourcePath) await notify(sourcePath) - }, - } -}) satisfies Plugin From de805a238b347bf6f404b88ae32f407336cb10ca Mon Sep 17 00:00:00 2001 From: Dario Coscia Date: Wed, 21 Oct 2026 20:18:16 +0200 Subject: [PATCH 6/7] affiliation cleaning and team rst --- MAINTAINERS.md | 2 +- STEERING-COMMITTEE.md | 2 +- docs/source/_team.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 34b988ee8..da71fa663 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -8,7 +8,7 @@ This document lists the Maintainers of the Project. Maintainers may be added onc | **GithubID** | **Email Address** | **Organization** | | ------------ | ------------------------ | ---------------------- | | @GiovanniCanali | giovanni.canali98@yahoo.it | SISSA | -| @dario-coscia | dariocos99@gmail.com | SISSA | +| @dario-coscia | dariocos99@gmail.com | CuspAI | | @ndem0 | demo.nicola@gmail.com | SISSA - FAST COMPUTING SRL | | @AleDinve | gdinvern@sissa.it | SISSA | | @annaivagnes | aivagnes@sissa.it | SISSA | diff --git a/STEERING-COMMITTEE.md b/STEERING-COMMITTEE.md index 156da704d..a44326596 100644 --- a/STEERING-COMMITTEE.md +++ b/STEERING-COMMITTEE.md @@ -5,7 +5,7 @@ This document lists the members of the Organization's Steering Committee (in alp | **NAME** | **Handle** | **Affiliated Organization** | | ------------ | ------------ | --------------------------- | | Giovanni Canali | @GiovanniCanali | SISSA | -| Dario Coscia | @dario-coscia | SISSA | +| Dario Coscia | @dario-coscia | CuspAI | | Nicola Demo | @ndem0 | SISSA - FAST COMPUTING SRL | --- diff --git a/docs/source/_team.rst b/docs/source/_team.rst index b8abdef58..a391266b2 100644 --- a/docs/source/_team.rst +++ b/docs/source/_team.rst @@ -5,7 +5,7 @@ PINA Team ========== -**PINA** is part of the `PyTorch ecosystem `_ and currently developed at the `SISSA MathLab `_, in collaboration with `Fast Computing `_. +**PINA** is part of the `PyTorch ecosystem `_ . .. image:: https://img.shields.io/badge/PyTorch%20ecosystem-EE4C2C?style=for-the-badge&logo=pytorch&logoColor=white&labelColor=555 :target: https://pytorch.landscape2.io/?item=modeling--ai-for-science-and-engineering--pina From 3a11df73775d60624ed18c48e699779ec09aace1 Mon Sep 17 00:00:00 2001 From: GiovanniCanali Date: Thu, 29 Oct 2026 11:42:36 +0100 Subject: [PATCH 7/7] add fundings section in README --- README.md | 70 ++++++++++++++++++ docs/source/_team.rst | 15 +--- docs/source/index.rst | 2 +- .../{foudings.png => fundings.png} | Bin 4 files changed, 73 insertions(+), 14 deletions(-) rename docs/source/index_files/{foudings.png => fundings.png} (100%) diff --git a/README.md b/README.md index 7ab06de48..fcf6d380d 100644 --- a/README.md +++ b/README.md @@ -381,6 +381,76 @@ If you would like to contribute, please read the
+ +
+ +

Fundings

+
+ +

+ A significant part of PINA has been developed either as a + by-product of funded research projects or through contributions + from researchers holding university-funded positions. + We gratefully acknowledge this support, particularly from: +

+ + + +
+ + ERC Logo + +
+ +

+ We also acknowledge the contribution of Maria Strazzullo to the early development of the package. + Special thanks go to all the students and researchers from different universities who have contributed to its development. + Finally, we warmly thank all the contributors + who are the true heart of PINA! +

+ +
+ + Contributing Universities + +
+ +
+
+ +

Citation

diff --git a/docs/source/_team.rst b/docs/source/_team.rst index a391266b2..fbd48acd0 100644 --- a/docs/source/_team.rst +++ b/docs/source/_team.rst @@ -5,23 +5,12 @@ PINA Team ========== -**PINA** is part of the `PyTorch ecosystem `_ . - -.. image:: https://img.shields.io/badge/PyTorch%20ecosystem-EE4C2C?style=for-the-badge&logo=pytorch&logoColor=white&labelColor=555 - :target: https://pytorch.landscape2.io/?item=modeling--ai-for-science-and-engineering--pina - :align: center - :width: 300 - -.. figure:: index_files/fast_mathlab.png - :align: center - :width: 500 - -A significant part of **PINA** has been written either as a by-product of funded projects or by people on university-funded positions. We are very grateful for this support. In particular, we acknowledge: +**PINA** is part of the `PyTorch ecosystem `_ . A significant part of **PINA** has been written either as a by-product of funded projects or by people on university-funded positions. We are very grateful for this support. In particular, we acknowledge: * `H2020 ERC CoG 2015 AROMA-CFD project 681447 `_, P.I. Professor `Prof. Gianluigi Rozza `_ at `SISSA MathLab `_. * `Next Generation EU `_ for environmental and digital transition in Italy. -.. figure:: index_files/foudings.png +.. figure:: index_files/fundings.png :align: center :width: 500 diff --git a/docs/source/index.rst b/docs/source/index.rst index 05ebef503..39d6c4773 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -185,7 +185,7 @@ Physics-Informed Neural Networks (PINNs), Neural Operators, and more. API <_rst/_code> Tutorials <_tutorial> Contributing <_contributing> - Team & Foundings <_team.rst> + Team & Fundings <_team.rst> Installing <_installation> Cite PINA <_cite.rst> License <_LICENSE.rst> diff --git a/docs/source/index_files/foudings.png b/docs/source/index_files/fundings.png similarity index 100% rename from docs/source/index_files/foudings.png rename to docs/source/index_files/fundings.png