Skip to content

Add Spin/Charge embeddings#183

Open
JonathanSchmidt1 wants to merge 16 commits intometatensor:mainfrom
JonathanSchmidt1:spin_charge
Open

Add Spin/Charge embeddings#183
JonathanSchmidt1 wants to merge 16 commits intometatensor:mainfrom
JonathanSchmidt1:spin_charge

Conversation

@JonathanSchmidt1
Copy link

Summary

This PR adds support for system-level charge and spin multiplicity conditioning
inputs (mtt::charge, mtt::spin) in the ASE calculator, allowing models that
declare these in requested_inputs() to receive them automatically.

Note: I did not take care yet of making this work with torch-sim, though torch-sim already supports system-wide charge and spin (though they have a default spin of 0)

ase_calculator.py:

  • Added SYSTEM_QUANTITIES dict mapping mtt::charge / mtt::spin to their
    atoms.info keys ("charge" / "spin"), defaults (0 / 1), and TensorMap
    construction logic.
  • Extended _get_ase_input to handle system-level scalar inputs from
    SYSTEM_QUANTITIES, storing values in the system's floating-point dtype
    (float32/float64) as required by system.add_data().
  • Added a check_state() override to MetatomicCalculator that detects changes
    to atoms.info["charge"] / atoms.info["spin"] and forces a fresh
    calculation, preventing stale cached results when only the charge or
    spin changes. The relevant keys are cached at construction time
    (_system_info_watch) to avoid per-step TorchScript dispatch overhead.

docs/src/engines/ase.rst:

  • Documented the two new system-level inputs, their defaults, and how to set
    them via atoms.info.

Tests (tests/ase_calculator.py): three new tests:

  • test_system_level_input — verifies correct dtype and value forwarding for
    charge and spin.
  • test_system_level_input_defaults — verifies defaults (charge=0, spin=1)
    when keys are absent from atoms.info.
  • test_system_level_input_changes_energy — regression test confirming that
    different charge values, different spin values, and atoms.info changes
    without an explicit reset() all produce different energies.
  • ChargeSpinAnisoModel — test confirming that a charge/spin model is symmetrized correctly
  • test_symmetrized_calculator_passes_charge_spin — test confirming that charges and spins are passed through the SymmetrizedCalculator

Contributor (creator of pull-request) checklist

  • Tests updated (for new features and bugfixes)?
  • Documentation updated (for new features)?
  • Issue referenced (for PRs that solve an issue)?

Reviewer checklist

  • CHANGELOG updated with public API or any other important changes?

Copy link
Contributor

@frostedoyster frostedoyster left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @JonathanSchmidt1! I would also ping @Luthaf who has a better idea of the design we want for these input quantities. One potential concern is that a model might be called with a charge/spin state that it doesn't support and we don't have a mechanism to prevent that. Models that don't support charges and spins will just ignore these charges and spins... which might be correct thing to do, but just checking

Comment on lines +62 to +63
system as the model's floating-point dtype (float32 or float64); the model
converts them back to integers internally for the embedding lookup.
Copy link
Contributor

@frostedoyster frostedoyster Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't necessarily say this in the documentation, simply because the implementation will potentially change (I think we're soon going to support integer TensorMaps, right @Luthaf?). I wouldn't say how the model is going to handle them either: the point of metatomic is to be totally generic, each model can handle these inputs how it wants (including ignoring them).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, integer TensorMap are already mostly supported at runtime and will soon be able to be serialized as well.

* - Input name
- Default
- How to set
* - ``"mtt::charge"``
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Charges and spins shouldn't be mtt:: anymore, they should be made standard inputs (so they don't need a prefix anymore)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, per-atom charge already are, we need to add total charge, per atom spin and total spin

@pfebrer pfebrer removed their request for review March 23, 2026 09:46
@pfebrer
Copy link

pfebrer commented Mar 23, 2026

This one is not for me to decide, I'll let Filippo and Guillaume review :)

@JonathanSchmidt1
Copy link
Author

One potential concern is that a model might be called with a charge/spin state that it doesn't support and we don't have a mechanism to prevent that. Models that don't support charges and spins will just ignore these charges and spins... which might be correct thing to do, but just checking

There is a check for models that support charge and spin to make sure they support the requested values (in the metatrain pr)
self.system_conditioning.validate(charges, spins)

outside of that I don't think we can solve this issue as we would have to output warnings for every key in atom.info in case they might be an input that the user expects the model to use.
On the other hand we could log the information if extra info is used (maybe make sure this log only happens once)

        for name, option in self._model.requested_inputs().items():
            input_tensormap = _get_ase_input(
                atoms, name, option, dtype=self._dtype, device=self._device
            )
            log.info(f"{name} requested as input")
            system.add_data(name, input_tensormap)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants