Skip to content

Add a heat flux wrapper#144

Open
GardevoirX wants to merge 17 commits intometatensor:mainfrom
GardevoirX:heat-flux-wrapper
Open

Add a heat flux wrapper#144
GardevoirX wants to merge 17 commits intometatensor:mainfrom
GardevoirX:heat-flux-wrapper

Conversation

@GardevoirX
Copy link
Contributor

@GardevoirX GardevoirX commented Jan 26, 2026

Closes #104

This is still in a very early stage and subjected to change.

TODO:

  • Interface for getting the heat flux from the model
  • Checks for the applicability of unfolding the system
  • Tests
  • Documentations
  • Remove Replace the dependency on vesin.metatomic with vesin.torch and rebuild neighbor list from the un-unfolded system (Hard to build the neighboring information between the replica atoms, e.g. atoms in different image boxes. And vesin.metatomic is not supposed to be used in metatomic.)

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?

@GardevoirX GardevoirX marked this pull request as ready for review February 24, 2026 22:00
@GardevoirX
Copy link
Contributor Author

GardevoirX commented Feb 24, 2026

I think this is now ready for reviewing. Though the current results with pet models are not good enough, soap-bpnn still gives some promising results. Plus, there's no evident bug in the current implementation. Perhaps a thorough checking for the code can reveal underlying problems.

In terms of the implementation, thie current state hasn't reached an ideal state. The calculation of the term1 of the heat flux can be implemented in a JVP style, but it is still in VJP and calculated through a for-loop. This might be improved after metatensor/metatensor#1063 is merged, but previous tests suggested that more blocks are in the path.

The second thing is how we do "unfolding" in _unfold_system. There could be two ways:

  1. The current way: check if particles are close to the box boundary, and generate the replicas if true.
  2. Do a NL calculation to get the atom pairs closer than the interaction range of the model, and then only unfolding the atoms in the pairs with non-zero shifting vector.

Tests showed that the second way can generate fewer atoms and thus can save runtime from the model inference, while an extra NL calculation also costs time. My intuition is that which one is faster depends on the system size.

Also maybe we need a tutorial about how to use this wrapper.

components=[Labels(["xyz"], torch.arange(3, device=device).reshape(-1, 1))],
properties=Labels(["heat_flux"], torch.tensor([[0]], device=device)),
)
results["extra::heat_flux"] = TensorMap(
Copy link
Member

Choose a reason for hiding this comment

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

Instead of having a custom output here, it would be better to also add heat_flux as a standard output =)

Comment on lines 18 to 23
HeatFluxWrapper,
_check_collisions,
_collisions_to_replicas,
_generate_replica_atoms,
_unfold_system,
_wrap_positions,
Copy link
Member

Choose a reason for hiding this comment

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

I don't love importing all private functions. The tests should test the public API, not the private implementation

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hmm then we would only have smoke tests?


self._requested_inputs = {
"masses": ModelOutput(quantity="mass", unit="u", per_atom=True),
"velocities": ModelOutput(quantity="velocity", unit="A/fs", per_atom=True),
Copy link
Member

Choose a reason for hiding this comment

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

This might not match the positions units required by the underlying model

Copy link
Member

Choose a reason for hiding this comment

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

Also, I'm not sure what happens if the underlying model already request these inputs but with a different unit. We should at least check & error.

per_atom=False,
)
outputs = self._model.capabilities().outputs.copy()
outputs["extra::heat_flux"] = hf_output
Copy link
Member

Choose a reason for hiding this comment

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

If we have multiple energy variant in the underlying model, I think this should expose multiple heat_flux variants with the same names/descriptions.

}

hf_output = ModelOutput(
quantity="heat_flux",
Copy link
Member

Choose a reason for hiding this comment

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

This does not exist right now, but we should add it!

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.

Implement a wrapper for heat flux calculation

2 participants