From 50a1b188bcaaf675eadd875018ee0b1c326a649d Mon Sep 17 00:00:00 2001 From: Guillaume Fraux Date: Mon, 2 Feb 2026 11:51:46 +0100 Subject: [PATCH 1/2] Use singular for property names in output metadata --- docs/src/outputs/charges.rst | 8 +- docs/src/outputs/energy.rst | 4 +- docs/src/outputs/features.rst | 4 +- docs/src/outputs/masses.rst | 11 +- docs/src/outputs/momenta.rst | 9 +- docs/src/outputs/non_conservative.rst | 16 +-- docs/src/outputs/positions.rst | 8 +- docs/src/outputs/velocities.rst | 9 +- metatomic-torch/CHANGELOG.md | 6 + metatomic-torch/src/outputs.cpp | 109 +++++++++++++++--- .../metatomic/torch/ase_calculator.py | 15 +-- 11 files changed, 136 insertions(+), 63 deletions(-) diff --git a/docs/src/outputs/charges.rst b/docs/src/outputs/charges.rst index 281477fa..79c44af2 100644 --- a/docs/src/outputs/charges.rst +++ b/docs/src/outputs/charges.rst @@ -3,8 +3,8 @@ Charges ^^^^^^^ -Charges are associated with the ``"charges"`` key in the model inputs, and must -adhere to the following metadata schema: +Charges are associated with the ``"charges"`` or ``"charges/"`` name +(see :ref:`output-variants`), and must have the following metadata: .. list-table:: Metadata for charges :widths: 2 3 7 @@ -36,8 +36,8 @@ adhere to the following metadata schema: - the charges must not have any components * - properties - - ``"charges"`` - - charges must have a single property dimension named ``"charges"``, with a + - ``"charge"`` + - charges must have a single property dimension named ``"charge"``, with a single entry set to ``0``. The following simulation engine can provide ``"charges"`` as inputs to the models. diff --git a/docs/src/outputs/energy.rst b/docs/src/outputs/energy.rst index e16bf3e2..e2d93e1c 100644 --- a/docs/src/outputs/energy.rst +++ b/docs/src/outputs/energy.rst @@ -3,8 +3,8 @@ Energy ^^^^^^ -Energy is associated with the ``"energy"`` or ``"energy/"`` key (see -:ref:`output-variants`) in the model outputs, and must have the following metadata: +Energy is associated with the ``"energy"`` or ``"energy/"`` name (see +:ref:`output-variants`), and must have the following metadata: .. list-table:: Metadata for energy output :widths: 2 3 7 diff --git a/docs/src/outputs/features.rst b/docs/src/outputs/features.rst index 25a322a0..f8bbcde2 100644 --- a/docs/src/outputs/features.rst +++ b/docs/src/outputs/features.rst @@ -15,8 +15,8 @@ by a neural-network or a similar machine learning construct. .. _Atom-centered symmetry functions: https://doi.org/10.1063/1.3553717 In metatomic models, they are associated with the ``"features"`` or -``"features/"`` key (see :ref:`output-variants`) key in the model -outputs, and must adhere to the following metadata specification: +``"features/"`` name (see :ref:`output-variants`), and must have the +following metadata: .. list-table:: Metadata for features output :widths: 2 3 7 diff --git a/docs/src/outputs/masses.rst b/docs/src/outputs/masses.rst index d84a6c56..41f89da6 100644 --- a/docs/src/outputs/masses.rst +++ b/docs/src/outputs/masses.rst @@ -3,8 +3,8 @@ Masses ^^^^^^ -Masses are associated with the ``"masses"`` key in the model -inputs, and must adhere to the following metadata schema: +Masses are associated with the ``"masses"`` or ``"masses/"`` name (see +:ref:`output-variants`), and must have the following metadata: .. list-table:: Metadata for masses :widths: 2 3 7 @@ -36,9 +36,9 @@ inputs, and must adhere to the following metadata schema: - the masses must not have any components * - properties - - ``"masses"`` - - masses must have a single property dimension named - ``"masses"``, with a single entry set to ``0``. + - ``"masse`` + - masses must have a single property dimension named ``"mass"``, with a + single entry set to ``0``. The following simulation engine can provide ``"masses"`` as inputs to the models. @@ -51,4 +51,3 @@ The following simulation engine can provide ``"masses"`` as inputs to the models :link-type: ref |ase-logo| - diff --git a/docs/src/outputs/momenta.rst b/docs/src/outputs/momenta.rst index 85e3d7af..cc74eb52 100644 --- a/docs/src/outputs/momenta.rst +++ b/docs/src/outputs/momenta.rst @@ -8,8 +8,8 @@ Predictions of momenta can be used, for example, to predict a future step in mol dynamics (see, e.g., https://arxiv.org/pdf/2505.19350). In metatomic models, they are associated with the ``"momenta"`` or -``"momenta/"`` key (see :ref:`output-variants`) key in the model -outputs, and must adhere to the following metadata schema: +``"momenta/"`` name (see :ref:`output-variants`), and must have the +following metadata: .. list-table:: Metadata for momenta :widths: 2 3 7 @@ -44,9 +44,9 @@ outputs, and must adhere to the following metadata schema: components is x, y, z. * - properties - - ``"momenta"`` + - ``"momentum"`` - momenta must have a single property dimension named - ``"momenta"``, with a single entry set to ``0``. + ``"momentum"``, with a single entry set to ``0``. The following simulation engine can provide ``"momenta"`` as inputs to the models. @@ -59,4 +59,3 @@ The following simulation engine can provide ``"momenta"`` as inputs to the model :link-type: ref |ase-logo| - diff --git a/docs/src/outputs/non_conservative.rst b/docs/src/outputs/non_conservative.rst index 9e94a257..202154f2 100644 --- a/docs/src/outputs/non_conservative.rst +++ b/docs/src/outputs/non_conservative.rst @@ -8,9 +8,9 @@ gradient of a potential energy function. These are generally faster to compute than forces derived from the potential energy by backpropagation. However, these predictions must be used with care, see https://arxiv.org/abs/2412.11569. -In metatomic models, they are associated with the ``"non_conservative_forces"`` or -``"non_conservative_forces/"`` key (see :ref:`output-variants`) in the model -outputs, and must adhere to the following metadata schema: +In metatomic models, they are associated with the ``"non_conservative_forces"`` +or ``"non_conservative_forces/"`` name (see :ref:`output-variants`), +and must have the following metadata: .. list-table:: Metadata for non-conservative forces :widths: 2 3 7 @@ -45,9 +45,9 @@ outputs, and must adhere to the following metadata schema: components is x, y, z. * - properties - - ``"non_conservative_forces"`` + - ``"non_conservative_force"`` - non-conservative forces must have a single property dimension named - ``"non_conservative_forces"``, with a single entry set to ``0``. + ``"non_conservative_force"``, with a single entry set to ``0``. The following simulation engines can use the ``"non_conservative_forces"`` output, using a ``non_conservative`` flag: @@ -95,9 +95,9 @@ not calculated using derivatives of the potential energy. As with forces, they are typically faster to compute but need to be used with care, see https://arxiv.org/abs/2412.11569. -In metatomic models, they are associated with the ``"non_conservative_stress"`` or -``"non_conservative_stress/"`` key (see :ref:`output-variants`) in the model -outputs, and must adhere to the following metadata schema: +In metatomic models, they are associated with the ``"non_conservative_stress"`` +or ``"non_conservative_stress/"`` name (see :ref:`output-variants`), +and must have the following metadata: .. list-table:: Metadata for non-conservative stress output :widths: 2 3 7 diff --git a/docs/src/outputs/positions.rst b/docs/src/outputs/positions.rst index 64513b2f..d06b650e 100644 --- a/docs/src/outputs/positions.rst +++ b/docs/src/outputs/positions.rst @@ -8,8 +8,8 @@ They can be used to predict the next configuration in molecular dynamics (see, e.g., https://arxiv.org/pdf/2505.19350). In metatomic models, they are associated with the ``"positions"`` or -``"positions/"`` key (see :ref:`output-variants`) key in the model -outputs, and must adhere to the following metadata schema: +``"positions/"`` name (see :ref:`output-variants`), and must have the +following metadata: .. list-table:: Metadata for positions :widths: 2 3 7 @@ -44,8 +44,8 @@ outputs, and must adhere to the following metadata schema: components is x, y, z. * - properties - - ``"positions"`` + - ``"position"`` - positions must have a single property dimension named - ``"positions"``, with a single entry set to ``0``. + ``"position"``, with a single entry set to ``0``. At the moment, positions are not integrated into any simulation engines. diff --git a/docs/src/outputs/velocities.rst b/docs/src/outputs/velocities.rst index 87ce8b63..7e0834f9 100644 --- a/docs/src/outputs/velocities.rst +++ b/docs/src/outputs/velocities.rst @@ -3,8 +3,9 @@ Velocities ^^^^^^^^^^ -Velocities are associated with the ``"velocities"`` key in the model -inputs, and must adhere to the following metadata schema: +Velocities are associated with the ``"velocities"`` or +``"velocities/"`` name (see :ref:`output-variants`), and must have the +following metadata: .. list-table:: Metadata for velocities :widths: 2 3 7 @@ -39,9 +40,9 @@ inputs, and must adhere to the following metadata schema: components is x, y, z. * - properties - - ``"velocities"`` + - ``"velocity"`` - velocities must have a single property dimension named - ``"velocities"``, with a single entry set to ``0``. + ``"velocity"``, with a single entry set to ``0``. The following simulation engine can provide ``"velocities"`` as inputs to the models. diff --git a/metatomic-torch/CHANGELOG.md b/metatomic-torch/CHANGELOG.md index 2a9fedfa..5f62b18d 100644 --- a/metatomic-torch/CHANGELOG.md +++ b/metatomic-torch/CHANGELOG.md @@ -17,6 +17,12 @@ a changelog](https://keepachangelog.com/en/1.1.0/) format. This project follows ### Removed --> +### Changed + +- Properties in standard output/inputs should now consistently use singular + (i.e. `position` instead of `positions`). The plural names are deprecated and + will be remove in the future. + ## [Version 0.1.7](https://github.com/metatensor/metatomic/releases/tag/metatomic-torch-v0.1.7) - 2025-11-26 ### Fixed diff --git a/metatomic-torch/src/outputs.cpp b/metatomic-torch/src/outputs.cpp index f77e7187..86aa23f1 100644 --- a/metatomic-torch/src/outputs.cpp +++ b/metatomic-torch/src/outputs.cpp @@ -326,9 +326,26 @@ static void check_non_conservative_forces( torch::tensor({{0}, {1}, {2}}, tensor_options) ) }; - validate_components("non_conservative_forces", forces_block->components(), expected_components); + Labels expected_properties; + if (forces_block->properties()->names()[0] == "non_conservative_forces") { + TORCH_WARN_ONCE( + "The 'non_conservative_forces' output uses a deprecated property name " + "'non_conservative_forces'. Please use 'non_conservative_force' (singular) instead." + ) + expected_properties = torch::make_intrusive( + "non_conservative_forces", + torch::tensor({{0}}, tensor_options) + ); + } else { + expected_properties = torch::make_intrusive( + "non_conservative_force", + torch::tensor({{0}}, tensor_options) + ); + } + validate_properties("non_conservative_forces", forces_block, expected_properties); + // Should not have any gradients validate_no_gradients("non_conservative_forces", forces_block); } @@ -355,6 +372,12 @@ static void check_non_conservative_stress( validate_components("non_conservative_stress", stress_block->components(), expected_components); + auto expected_properties = torch::make_intrusive( + "non_conservative_stress", + torch::tensor({{0}}, tensor_options) + ); + validate_properties("non_conservative_stress", stress_block, expected_properties); + // Should not have any gradients validate_no_gradients("non_conservative_stress", stress_block); } @@ -382,10 +405,22 @@ static void check_positions( validate_components("positions", positions_block->components(), expected_components); - auto expected_properties = torch::make_intrusive( - "positions", - torch::tensor({{0}}, tensor_options) - ); + Labels expected_properties; + if (positions_block->properties()->names()[0] == "positions") { + TORCH_WARN_ONCE( + "The 'positions' output uses a deprecated property name 'positions'. " + "Please use 'position' (singular) instead." + ) + expected_properties = torch::make_intrusive( + "positions", + torch::tensor({{0}}, tensor_options) + ); + } else { + expected_properties = torch::make_intrusive( + "position", + torch::tensor({{0}}, tensor_options) + ); + } validate_properties("positions", positions_block, expected_properties); // Should not have any gradients @@ -404,7 +439,6 @@ static void check_momenta( // Check samples values from systems validate_atomic_samples("momenta", value, systems, request, torch::nullopt); - auto tensor_options = torch::TensorOptions().device(value->device()); auto momenta_block = TensorMapHolder::block_by_id(value, 0); std::vector expected_component { @@ -415,10 +449,22 @@ static void check_momenta( }; validate_components("momenta", momenta_block->components(), expected_component); - auto expected_properties = torch::make_intrusive( - "momenta", - torch::tensor({{0}}, tensor_options) - ); + Labels expected_properties; + if (momenta_block->properties()->names()[0] == "momenta") { + TORCH_WARN_ONCE( + "The 'momenta' output uses a deprecated property name 'momenta'. " + "Please use 'momentum' (singular) instead." + ) + expected_properties = torch::make_intrusive( + "momenta", + torch::tensor({{0}}, tensor_options) + ); + } else { + expected_properties = torch::make_intrusive( + "momentum", + torch::tensor({{0}}, tensor_options) + ); + } validate_properties("momenta", momenta_block, expected_properties); // Should not have any gradients @@ -443,10 +489,22 @@ static void check_masses( // Ensure that the block has no components validate_components("masses", masses_block->components(), {}); - auto expected_properties = torch::make_intrusive( - "masses", - torch::tensor({{0}}, tensor_options) - ); + Labels expected_properties; + if (masses_block->properties()->names()[0] == "masses") { + TORCH_WARN_ONCE( + "The 'masses' output uses a deprecated property name 'masses'. " + "Please use 'mass' (singular) instead." + ) + expected_properties = torch::make_intrusive( + "masses", + torch::tensor({{0}}, tensor_options) + ); + } else { + expected_properties = torch::make_intrusive( + "mass", + torch::tensor({{0}}, tensor_options) + ); + } validate_properties("masses", masses_block, expected_properties); // Should not have any gradients @@ -475,10 +533,23 @@ static void check_velocities( }; validate_components("velocities", velocities_block->components(), expected_component); - auto expected_properties = torch::make_intrusive( - "velocities", - torch::tensor({{0}}, tensor_options) - ); + Labels expected_properties; + if (velocities_block->properties()->names()[0] == "velocities") { + TORCH_WARN_ONCE( + "The 'velocities' output uses a deprecated property name 'velocities'. " + "Please use 'velocity' (singular) instead." + ) + expected_properties = torch::make_intrusive( + "velocities", + torch::tensor({{0}}, tensor_options) + ); + } else { + expected_properties = torch::make_intrusive( + "velocity", + torch::tensor({{0}}, tensor_options) + ); + } + validate_properties("velocities", velocities_block, expected_properties); // Should not have any gradients @@ -504,7 +575,7 @@ static void check_charges( validate_components("charges", charges_block->components(), {}); auto expected_properties = torch::make_intrusive( - "charges", + "charge", torch::tensor({{0}}, tensor_options) ); validate_properties("charges", charges_block, expected_properties); diff --git a/python/metatomic_torch/metatomic/torch/ase_calculator.py b/python/metatomic_torch/metatomic/torch/ase_calculator.py index 84af73ab..0f2dbf0a 100644 --- a/python/metatomic_torch/metatomic/torch/ase_calculator.py +++ b/python/metatomic_torch/metatomic/torch/ase_calculator.py @@ -998,6 +998,10 @@ def _get_ase_input( # for metatensor values = torch.tensor(values[..., None]) + components = [] + if values.shape[1] != 1: + components.append(Labels(["xyz"], torch.arange(values.shape[1]).reshape(-1, 1))) + block = TensorBlock( values, samples=Labels( @@ -1006,15 +1010,8 @@ def _get_ase_input( [torch.full((values.shape[0],), 0), torch.arange(values.shape[0])] ).T, ), - components=[Labels(["xyz"], torch.arange(values.shape[1]).reshape(-1, 1))] - if values.shape[1] != 1 - else [], - properties=Labels( - [ - name if "::" not in name else name.split("::")[-1], - ], - torch.tensor([[0]]), - ), + components=components, + properties=Labels([infos["quantity"]], torch.tensor([[0]])), ) tensor = TensorMap(Labels(["_"], torch.tensor([[0]])), [block]) From ba8afeed3ae409348fe0fa5b7b2d8c27ee04ba68 Mon Sep 17 00:00:00 2001 From: Guillaume Fraux Date: Mon, 2 Feb 2026 14:45:46 +0100 Subject: [PATCH 2/2] Update docs/src/outputs/masses.rst Co-authored-by: Rohit Goswami --- docs/src/outputs/masses.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/outputs/masses.rst b/docs/src/outputs/masses.rst index 41f89da6..cba6f9c4 100644 --- a/docs/src/outputs/masses.rst +++ b/docs/src/outputs/masses.rst @@ -36,7 +36,7 @@ Masses are associated with the ``"masses"`` or ``"masses/"`` name (see - the masses must not have any components * - properties - - ``"masse`` + - ``"mass`` - masses must have a single property dimension named ``"mass"``, with a single entry set to ``0``.