Skip to content

Fix Sab / intensity calculations#110

Merged
mducle merged 32 commits intomainfrom
sab_deb
Mar 6, 2026
Merged

Fix Sab / intensity calculations#110
mducle merged 32 commits intomainfrom
sab_deb

Conversation

@mducle
Copy link
Copy Markdown
Member

@mducle mducle commented Jan 23, 2026

This PR ensures that output from PySpinW agrees with Matlab SpinW numerically. There were a couple of errors in the computations:

  • A missing $2\pi$ in the intensity phase factor calculation
  • The distance in the phase factor calculation of the Hamiltonian which we call the inter_site_vector is actually the vector between unit cells (G) rather than the full vector between the sites.
  • The transformation matrix T is actually adjoint(L) \ U * sqrt(E) rather than L \ U * sqrt(E) - in Matlab they use a Cholesky decomposition which yields an upper-triangular K whereas we use the LDL decomposition which yields a lower triangular L but the computation only works for an upper-triangular matrix.
  • In hamiltonian.py the calculation of reverse couplings was missing the double counting factor of 1/2
  • The computation of distances for the couplings used the wrong transform (should not be transposed).
  • The calculation of the orthogonal basis vectors e1, e2, e3 had e2 parallel to [0,1,0] if e3 is parallel to [1,0,0] but the Matlab code had it parallel to [0,0,1] - and this caused the kagome_supercell calculation to fail (not sure why).
  • Add code to remove duplicate couplings in the Hamiltonian calculations.

In addition, I changed the driver routines to correct the above mistakes; and also added more examples from the Matlab test suite.

However, there are two major discrepancies between the theory presented in Toth & Lake and the Matlab implementation:

  1. There is an additional factor of 2 in the Matlab Hamiltonian calculation of the single-ion anisotropy terms (called A20 / D20 in the code, computed in lines 618-9 compared to the $C^{i,j}$ terms in eq (26) of the paper.
  2. The scaling of the Matlab Sab calculation (line 1096) is different to equation (47) of the paper's which gives a prefactor of $1/(2N)$ where $N$ is the number of atoms in the unit cell, but the Matlab code uses 1/(2*prod(nExt)) (factor of 1/2 is in line 1066) which is the number of unit cells in the supercell - e.g. the Matlab code computes the intensity per unit cell whereas the theory gives it per magnetic atom.

In this PR I've added code to make the Python calculations consistent with the Matlab, but we might want to make it such that it agrees with the paper instead.

* Had to modify the antiferro_chain.py model
* Fix missing 2pi in spin-spin phase factor
* Fix use of lower triangular factor in decomposition
  We use LDL whereas Matlab code uses Cholesky
  and the inv() of upper or lower triangles are v.
  different;
* TODO: investigate why maths only work for u-tri
* Change to using adjoint of T matrix instead of just transpose.
  Now numbers agree exactly with Matlab (previously off by 5%)
* Remove sorting in Python code - this swapped the order of the
  energies (eigenvalues) and intensities (eigenvectors) in
  subsequent calculations and is incorrect - it was only used
  because the Python was a copy of the rust code which used a -1
  multiply but we can just take the abs for the sqrt(E) calcs.
Copy link
Copy Markdown
Collaborator

@lucas-wilkins lucas-wilkins left a comment

Choose a reason for hiding this comment

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

There's some more work to be done on how the q points scale with the supercell, and I'm not 100% sure things will work right treating as you have here. I think we need a layer of converting q in and out of RLU, or things will get very confusing. Not saying that should be done here, in fact, I have previously made an issue for this #102 .

Comment thread src/spinwave.rs Outdated
Comment thread pyspinw/hamiltonian.py
unique_id_to_index[input_coupling.site_1._unique_id],
np.array(input_coupling.coupling_matrix.T, **rust_kw),
-input_coupling.vector(expanded.structure.unit_cell)
-input_coupling.cell_offset.vector.astype('double')
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This has changed from cartesian to LU coordinates, were you aware of this? is this the bugfix?

Copy link
Copy Markdown
Member Author

@mducle mducle Feb 9, 2026

Choose a reason for hiding this comment

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

is this the bugfix?

Yes. I think that we need this in lattice units rather than Cartesian... I'm not 100% sure but in the original code many of the examples fail with nonsensical energies...

Comment thread pyspinw/hamiltonian.py Outdated
Comment thread pyspinw/hamiltonian.py Outdated
Comment thread pyspinw/hamiltonian.py Outdated
Comment thread pyspinw/hamiltonian.py Outdated
Comment thread pyspinw/hamiltonian.py Outdated
Comment thread pyspinw/hamiltonian.py Outdated
Comment thread pyspinw/lattice_distances.py Outdated
Comment thread pyspinw/symmetry/supercell.py
@lucas-wilkins
Copy link
Copy Markdown
Collaborator

I'm still very skeptical about this. Fundamentally, I think the calculation should be invariant to the choice of unit cell, and I don't think this solution achieves that, even after correcting for the supercell scaling.

mducle added 17 commits February 8, 2026 22:19
* Include double counting factor of 1/2 in calculation of reverse couplings
* Fix cartesian transformation bug in lattice_distances (no transpose)
* Revert limits calculations (-l,l) vs (0,l) in lattice_distances
* Allow LaticeSite "moments" to be basisstate (can be complex)
  This requires taking the real part in supercell.expand()
* Update antiferromagnetic_chain, af_with_field, kagome_ferromagnet
* Add kagome_antiferromagnet (tutorial 7)
* Add triangular_antiferromagnet (tutorial 12)
* Add support for LU (lattice units) units in LatticeSite
* Change rust to make sqrt_hamiltonian mutable and remove kk
* Rename variables in hamiltonian.py
* Remove StrEnum as not in Python 3.10
* Fix hamiltonian.py code as called with unnormed transformation
* Propagate LatticeSite unit in Structure
* Remove old incorrect lattice_distance comment
* Fix af_with_field example coupling distance as changed lattice pars
* Previous rust code was not adding delta to diagonal
* Handles changes Py3.11 <-> 3.12 in numpy where the LinAlgError
  was not triggered giving a matrix with NaNs (in 3.11)
* Change limits of ferromagnetic chain example to exclude (100)
  where the intensity diverges and rust and Python disagree
Refactor to remove lu unit from LatticeSite class
Add spin length/magnitude to LatticeSite class
  this means that mi,mj,mk can just indicate direction
  consistent with Matlab code
Update examples code to use genmagstr
@mducle mducle marked this pull request as ready for review February 23, 2026 09:11
@mducle mducle marked this pull request as draft February 23, 2026 09:22
Fix matlab docstring code in examples
Remove unneeded imports
Remove debug_plot
Plot only positive energies in some examples to make it clearer
* Remove magnitude from LatticeSite / corresponding Structures
* Refactor genmagstr to define magnitude in its own args
* Add complex numpy array serialisation functionality
@mducle mducle marked this pull request as ready for review March 2, 2026 20:01
@mducle
Copy link
Copy Markdown
Member Author

mducle commented Mar 2, 2026

@lucas-wilkins I think this is ready for review... There is still a scale factor discrepancy in the intensity calculation but there's so much in this already I want to merge it before doing another PR for that fix (which I would need to investigate in more detail but don't have much time this week).

Copy link
Copy Markdown
Collaborator

@alexhroom alexhroom left a comment

Choose a reason for hiding this comment

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

just reviewing the Rust as you asked - mostly quality code, just a few little bits here and there for performance

Comment thread src/spinwave.rs Outdated
Comment thread src/spinwave.rs Outdated
Comment thread src/spinwave.rs
Comment thread src/lib.rs Outdated
Comment thread src/lib.rs Outdated
Copy link
Copy Markdown
Collaborator

@alexhroom alexhroom left a comment

Choose a reason for hiding this comment

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

happy with the Rust now!

@mducle mducle merged commit 1018491 into main Mar 6, 2026
13 checks passed
@mducle mducle deleted the sab_deb branch March 6, 2026 09:41
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.

3 participants