Skip to content

Commit 3ecded8

Browse files
committed
factored out the calculation per q into its own function
1 parent e4c361f commit 3ecded8

File tree

1 file changed

+67
-61
lines changed

1 file changed

+67
-61
lines changed

pyspinw/calculations/spinwave.py

+67-61
Original file line numberDiff line numberDiff line change
@@ -54,96 +54,102 @@ def spinwave_calculation(rotations: np.ndarray,
5454
z_conj = z.conj()
5555
eta = rotations[:,:,2] # n-by-3 real
5656

57-
# Create the A, B, and C matrices
58-
5957
# Create the matrix sqrt(S_i S_j)/2
6058
root_mags = np.sqrt(0.5*magnitudes) # S_i / sqrt(2)
6159
spin_coefficients = root_mags.reshape(-1, 1) * root_mags.reshape(1, -1)
6260

6361
energies = []
6462
methods = []
65-
for q in q_vectors:
66-
67-
A = np.zeros((n_sites, n_sites), dtype=complex)
68-
B = np.zeros((n_sites, n_sites), dtype=complex)
69-
C = np.zeros((n_sites, n_sites), dtype=complex)
7063

71-
# Add the terms up to the total spin coefficient
72-
for coupling in couplings:
64+
# calculate the C matrix for h(q), which is q-independent
65+
C = np.zeros((n_sites, n_sites), dtype=complex)
66+
for coupling in couplings:
67+
j = coupling.index2
68+
for l in range(n_sites):
69+
C[j, j] += spin_coefficients[l,l] * eta[j, :].T @ coupling.matrix @ eta[l, :]
7370

74-
phase_factor = np.exp((2j*np.pi)*np.dot(q, coupling.inter_site_vector))
71+
C *= 2
7572

76-
i = coupling.index1
77-
j = coupling.index2
73+
for q in q_vectors:
74+
eigenvalues, method = spinwave_calculation_single_q(q, C, n_sites, z, z_conj, spin_coefficients, couplings)
75+
energies.append(eigenvalues) # These are currently the square energies
76+
methods.append(method)
7877

79-
A[i, j] += z[i, :] @ coupling.matrix @ z_conj[j, :] * phase_factor
80-
B[i, j] += z[i, :] @ coupling.matrix @ z[j, :] * phase_factor
78+
return SpinwaveResult(
79+
q_vectors=q_vectors,
80+
raw_energies=energies,
81+
method=methods)
8182

8283

83-
for l in range(n_sites):
84-
C[j, j] += spin_coefficients[l,l] * eta[j, :].T @ coupling.matrix @ eta[l, :]
84+
def spinwave_calculation_single_q(q: float,
85+
C: np.ndarray,
86+
n_sites: int,
87+
z: np.ndarray,
88+
z_conj: np.ndarray,
89+
spin_coefficients: np.ndarray,
90+
couplings: list[Coupling]):
91+
"""Calculate the energies for the 'Hamiltonian' h(q) for a single q-value."""
92+
A = np.zeros((n_sites, n_sites), dtype=complex)
93+
B = np.zeros((n_sites, n_sites), dtype=complex)
8594

86-
A *= spin_coefficients
87-
B *= spin_coefficients
88-
C *= 2
89-
#
90-
# print("A", A)
91-
# print("B", B)
92-
# print("C", C)
95+
# Add the terms up to the total spin coefficient
96+
for coupling in couplings:
9397

98+
phase_factor = np.exp((2j*np.pi)*np.dot(q, coupling.inter_site_vector))
9499

95-
# hamiltonian_matrix = np.block([[A - C, B], [B.conj().T, A.conj().T - C]])
96-
hamiltonian_matrix = np.block([[A - C, B], [B.conj().T, A.conj().T - C]])
100+
i = coupling.index1
101+
j = coupling.index2
97102

98-
#
99-
# We need to enforce the bosonic commutation properties, we do this
100-
# by finding the 'square root' of the matrix (i.e. finding K such that KK^dagger = H)
101-
# and then negating the second half.
102-
#
103-
# In matrix form we do
104-
#
105-
# M = K^dagger C K
106-
#
107-
# where C is a diagonal matrix of length 2n, with the first n entries being 1, and the
108-
# remaining entries being -1. Note the adjoint is on the other side to the definition in
109-
# of the decomposition
110-
#
111-
# We can also do this via an LDL decomposition, but the method is very slightly different
103+
A[i, j] += z[i, :] @ coupling.matrix @ z_conj[j, :] * phase_factor
104+
B[i, j] += z[i, :] @ coupling.matrix @ z[j, :] * phase_factor
112105

113106

114-
try:
115-
sqrt_hamiltonian = np.linalg.cholesky(hamiltonian_matrix)
107+
A *= spin_coefficients
108+
B *= spin_coefficients
109+
#
110+
# print("A", A)
111+
# print("B", B)
112+
# print("C", C)
116113

117-
sqrt_hamiltonian_with_commutation = sqrt_hamiltonian.copy()
118-
sqrt_hamiltonian_with_commutation[:, n_sites:] *= -1
119114

120-
to_diagonalise = np.conj(sqrt_hamiltonian_with_commutation).T @ sqrt_hamiltonian
115+
# hamiltonian_matrix = np.block([[A - C, B], [B.conj().T, A.conj().T - C]])
116+
hamiltonian_matrix = np.block([[A - C, B], [B.conj().T, A.conj().T - C]])
121117

122-
methods.append(CalculationMethod.CHOLESKY)
118+
#
119+
# We need to enforce the bosonic commutation properties, we do this
120+
# by finding the 'square root' of the matrix (i.e. finding K such that KK^dagger = H)
121+
# and then negating the second half.
122+
#
123+
# In matrix form we do
124+
#
125+
# M = K^dagger C K
126+
#
127+
# where C is a diagonal matrix of length 2n, with the first n entries being 1, and the
128+
# remaining entries being -1. Note the adjoint is on the other side to the definition in
129+
# of the decomposition
130+
#
131+
# We can also do this via an LDL decomposition, but the method is very slightly different
123132

124-
except np.linalg.LinAlgError: # Catch postive definiteness errors
125133

134+
try:
135+
sqrt_hamiltonian = np.linalg.cholesky(hamiltonian_matrix)
136+
method = CalculationMethod.CHOLESKY
126137

127-
# l, d, perm = ldl(hamiltonian_matrix) # To LDL^\dagger (i.e. adjoint on right)
128-
l, d, _ = ldl(hamiltonian_matrix) # To LDL^\dagger (i.e. adjoint on right)
129-
sqrt_hamiltonian = l @ np.sqrt(d)
138+
except np.linalg.LinAlgError: # Catch postive definiteness errors
139+
# l, d, perm = ldl(hamiltonian_matrix) # To LDL^\dagger (i.e. adjoint on right)
140+
l, d, _ = ldl(hamiltonian_matrix) # To LDL^\dagger (i.e. adjoint on right)
141+
sqrt_hamiltonian = l @ np.sqrt(d)
130142

131-
# TODO: Check for actual diagonal (could potentially contain non-diagonal 2x2 blocks)
143+
# TODO: Check for actual diagonal (could potentially contain non-diagonal 2x2 blocks)
144+
method = CalculationMethod.LDL
132145

133-
sqrt_hamiltonian_with_commutation = sqrt_hamiltonian.copy()
134-
sqrt_hamiltonian_with_commutation[:, n_sites:] *= -1
135146

136-
to_diagonalise = np.conj(sqrt_hamiltonian_with_commutation).T @ sqrt_hamiltonian
147+
sqrt_hamiltonian_with_commutation = sqrt_hamiltonian.copy()
148+
sqrt_hamiltonian_with_commutation[:, n_sites:] *= -1
137149

138-
methods.append(CalculationMethod.LDL)
150+
to_diagonalise = np.conj(sqrt_hamiltonian_with_commutation).T @ sqrt_hamiltonian
139151

140-
eig_res = np.linalg.eig(to_diagonalise)
152+
return np.linalg.eigvals(to_diagonalise), method
141153

142-
energies.append(eig_res.eigenvalues) # These are currently the square energies
143154

144-
# pylint: enable=C0103
145155

146-
return SpinwaveResult(
147-
q_vectors=q_vectors,
148-
raw_energies=energies,
149-
method=methods)

0 commit comments

Comments
 (0)