OPAL (Object Oriented Parallel Accelerator Library) 2022.1
OPAL
RealDiracMatrix.cpp
Go to the documentation of this file.
1//
2// Class: RealDiracMatrix
3// Real Dirac matrix class.
4// They're ordered after the paper of Dr. C. Baumgarten: "Use of real Dirac matrices in two-dimensional coupled linear optics".
5// The diagonalizing method is based on the paper "Geometrical method of decoupling" (2012) of Dr. C. Baumgarten.
6//
7// Copyright (c) 2014, 2020 Christian Baumgarten, Paul Scherrer Institut, Villigen PSI, Switzerland
8// Matthias Frey, ETH Zürich
9// All rights reserved
10//
11// Implemented as part of the Semester thesis by Matthias Frey
12// "Matched Distributions in Cyclotrons"
13//
14// This file is part of OPAL.
15//
16// OPAL is free software: you can redistribute it and/or modify
17// it under the terms of the GNU General Public License as published by
18// the Free Software Foundation, either version 3 of the License, or
19// (at your option) any later version.
20//
21// You should have received a copy of the GNU General Public License
22// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
23//
24#include "RealDiracMatrix.h"
25
27
28#include <cmath>
29#include <string>
31
33
36 sparse_matrix_t rdm(4,4,4); // #nrows, #ncols, #non-zeros
37 switch(i) {
38 case 0: rdm(0,1) = rdm(2,3) = 1; rdm(1,0) = rdm(3,2) = -1; break;
39 case 1: rdm(0,1) = rdm(1,0) = -1; rdm(2,3) = rdm(3,2) = 1; break;
40 case 2: rdm(0,3) = rdm(1,2) = rdm(2,1) = rdm(3,0) = 1; break;
41 case 3: rdm(0,0) = rdm(2,2) = -1; rdm(1,1) = rdm(3,3) = 1; break;
42 case 4: rdm(0,0) = rdm(3,3) = -1; rdm(1,1) = rdm(2,2) = 1; break;
43 case 5: rdm(0,2) = rdm(2,0) = 1; rdm(1,3) = rdm(3,1) = -1; break;
44 case 6: rdm(0,1) = rdm(1,0) = rdm(2,3) = rdm(3,2) = 1; break;
45 case 7: rdm(0,3) = rdm(2,1) = 1; rdm(1,2) = rdm(3,0) = -1; break;
46 case 8: rdm(0,1) = rdm(3,2) = 1; rdm(1,0) = rdm(2,3) = -1; break;
47 case 9: rdm(0,2) = rdm(1,3) = -1; rdm(2,0) = rdm(3,1) = 1; break;
48 case 10: rdm(0,2) = rdm(3,1) = 1; rdm(1,3) = rdm(2,0) = -1; break;
49 case 11: rdm(0,2) = rdm(1,3) = rdm(2,0) = rdm(3,1) = -1; break;
50 case 12: rdm(0,0) = rdm(1,1) = -1; rdm(2,2) = rdm(3,3) = 1; break;
51 case 13: rdm(0,3) = rdm(3,0) = -1; rdm(1,2) = rdm(2,1) = 1; break;
52 case 14: rdm(0,3) = rdm(1,2) = -1; rdm(2,1) = rdm(3,0) = 1; break;
53 case 15: rdm(0,0) = rdm(1,1) = rdm(2,2) = rdm(3,3) = 1; break;
54 default: throw OpalException("RealDiracMatrix::getRDM()",
55 "Index (i = " + std::to_string(i)
56 + " out of range: 0 <= i <= 15"); break;
57 }
58 return rdm;
59}
60
61
63
64 // R and invR store the total transformation
65 R = boost::numeric::ublas::identity_matrix<double>(4);
66 invR = R;
67
68 vector_t P(3), E(3), B(3), b;
69 double mr, mg, mb, eps;
70
71 // Lambda function to compute vectors E, P, B and scalar eps (it takes the current Ms as reference argument (--> [&])
72 auto mult = [&](short i) {
73 /*
74 * For computing E, P, B, eps according to formula (C4) from paper:
75 * Geometrical method of decoupling
76 */
78 return 0.125*matt_boost::trace(tmp);
79 };
80
81 // 1. Transformation with \gamma_{0}
82 P = vector_t({ mult(1), mult(2), mult(3)});
83 E = vector_t({ mult(4), mult(5), mult(6)});
84 B = vector_t({-mult(7), -mult(8), -mult(9)});
85 mr = boost::numeric::ublas::inner_prod(E, B); // formula (31), paper: Geometrical method of decoupling
86 mg = boost::numeric::ublas::inner_prod(B, P); // formula (31), paper: Geometrical method of decoupling
87
88 transform(Ms, 0, 0.5 * std::atan2(mg,mr), R, invR);
89
90 // 2. Transformation with \gamma_{7}
91 eps = -mult(0);
92 P = vector_t({ mult(1), mult(2), mult(3)});
93 E = vector_t({ mult(4), mult(5), mult(6)});
94 B = vector_t({-mult(7), -mult(8), -mult(9)});
95 b = eps * B + matt_boost::cross_prod(E, P); // formula (32), paper: Geometrical method of decoupling
96
97 transform(Ms, 7, 0.5 * std::atan2(b(2), b(1)), R, invR);
98
99 // 3. Transformation with \gamma_{9}
100 eps = -mult(0);
101 P = vector_t({ mult(1), mult(2), mult(3)});
102 E = vector_t({ mult(4), mult(5), mult(6)});
103 B = vector_t({-mult(7), -mult(8), -mult(9)});
104 b = eps * B + matt_boost::cross_prod(E, P);
105
106 transform(Ms, 9, -0.5 * std::atan2(b(0), b(1)), R, invR);
107
108 // 4. Transformation with \gamma_{2}
109 eps = -mult(0);
110 P = vector_t({ mult(1), mult(2), mult(3)});
111 E = vector_t({ mult(4), mult(5), mult(6)});
112 B = vector_t({-mult(7), -mult(8), -mult(9)});
113 mr = boost::numeric::ublas::inner_prod(E, B);
114 b = eps * B + matt_boost::cross_prod(E, P);
115
116 // Transformation distinction made according to function "rdm_Decouple_F"
117 // in rdm.c of Dr. Christian Baumgarten
118
119 if (std::fabs(mr) < std::fabs(b(1))) {
120 transform(Ms, 2, 0.5 * std::atanh(mr / b(1)), R, invR);
121 } else {
122 transform(Ms, 2, 0.5 * std::atanh(b(1) / mr), R, invR);
123 }
124
125 eps = -mult(0);
126 P = vector_t({ mult(1), mult(2), mult(3)});
127 E = vector_t({ mult(4), mult(5), mult(6)});
128 B = vector_t({-mult(7), -mult(8), -mult(9)});
129
130 // formula (31), paper: Geometrical method of decoupling
131 mr = boost::numeric::ublas::inner_prod(E, B);
132 mg = boost::numeric::ublas::inner_prod(B, P);
133 mb = boost::numeric::ublas::inner_prod(E, P);
134
135 double P2 = boost::numeric::ublas::inner_prod(P, P);
136 double E2 = boost::numeric::ublas::inner_prod(E, E);
137
138 // 5. Transform with \gamma_{0}
139 transform(Ms, 0, 0.25 * std::atan2(mb,0.5 * (E2 - P2)), R, invR);
140
141 // 6. Transformation with \gamma_{8}
142 P(0) = mult(1); P(2) = mult(3);
143
144 transform(Ms, 8, -0.5 * std::atan2(P(2), P(0)), R, invR);
145}
146
147
151
152 sparse_matrix_t R = boost::numeric::ublas::identity_matrix<double>(4);
153 sparse_matrix_t invR = boost::numeric::ublas::identity_matrix<double>(4);
154 sparse_matrix_t iRtot = boost::numeric::ublas::identity_matrix<double>(4);
155
156 for (int i = 0; i < 6; ++i) {
157 update(sigma, i, R, invR);
158
159 iRtot = boost::numeric::ublas::prod(iRtot, invR);
160 S = matt_boost::gemmm<matrix_t>(R, S, invR);
161 sigma = - boost::numeric::ublas::prod(S, getRDM(0));
162 }
163
164 return iRtot;
165}
166
167
170 /*
171 * formula(16), p. 3
172 */
173 sparse_matrix_t rdm0 = getRDM(0);
174 return 0.5 * (M + matt_boost::gemmm<matrix_t>(rdm0,boost::numeric::ublas::trans(M),rdm0));
175}
176
177
178void RealDiracMatrix::transform(matrix_t& M, short i, double phi,
179 sparse_matrix_t& Rtot, sparse_matrix_t& invRtot)
180{
181 if (phi) { // if phi == 0 --> nothing happens, since R and invR would be identity_matrix matrix
182 sparse_matrix_t R(4,4), invR(4,4);
183
184 transform(i, phi, R, invR);
185
186 // update matrices
187 M = matt_boost::gemmm<matrix_t>(R,M,invR);
188 Rtot = boost::numeric::ublas::prod(R,Rtot);
189 invRtot = boost::numeric::ublas::prod(invRtot,invR);
190 }
191}
192
193
194void RealDiracMatrix::transform(short i, double phi,
196{
197 if (phi) { // if phi == 0 --> nothing happens, since R and invR would be identity_matrix matrix
198 sparse_matrix_t I = boost::numeric::ublas::identity_matrix<double>(4);
199
200 if ((i < 7 && i != 0) || (i > 10 && i != 14)) {
201 R = I * std::cosh(phi) + getRDM(i) * std::sinh(phi);
202 invR = I * std::cosh(phi) - getRDM(i) * std::sinh(phi);
203 } else {
204 R = I * std::cos(phi) + getRDM(i) * std::sin(phi);
205 invR = I * std::cos(phi) - getRDM(i) * std::sin(phi);
206 }
207 }
208}
209
210
212 sparse_matrix_t& invR)
213{
214 double s0 = 0.25 * ( sigma(0, 0) + sigma(1, 1) + sigma(2, 2) + sigma(3, 3) );
215 double s1 = 0.25 * (-sigma(0, 0) + sigma(1, 1) + sigma(2, 2) - sigma(3, 3) );
216 double s2 = 0.5 * ( sigma(0, 2) - sigma(1, 3) );
217 double s3 = 0.5 * ( sigma(0, 1) + sigma(2, 3) );
218 double s4 = 0.5 * ( sigma(0, 1) - sigma(2, 3) );
219 double s5 = -0.5 * ( sigma(0, 3) + sigma(1, 2) );
220 double s6 = 0.25 * ( sigma(0, 0) - sigma(1, 1) + sigma(2, 2) - sigma(3, 3) );
221 double s7 = 0.5 * ( sigma(0, 2) + sigma(1, 3) );
222 double s8 = 0.25 * ( sigma(0, 0) + sigma(1, 1) - sigma(2, 2) - sigma(3, 3) );
223 double s9 = 0.5 * ( sigma(0, 3) - sigma(1, 2) );
224
225 vector_t P(3); P(0) = s1; P(1) = s2; P(2) = s3;
226 vector_t E(3); E(0) = s4; E(1) = s5; E(2) = s6;
227 vector_t B(3); B(0) = s7; B(1) = s8; B(2) = s9;
228
229 double mr = boost::numeric::ublas::inner_prod(E, B);
230 double mg = boost::numeric::ublas::inner_prod(B, P);
231 double mb = boost::numeric::ublas::inner_prod(E, P);
232
233 vector_t b = -s0 * B + matt_boost::cross_prod(E, P);
234
235 switch (i) {
236 case 0:
237 {
238 double eps = std::atan2(mg, mr);
239 transform(0, 0.5 * eps, R, invR);
240 break;
241 }
242 case 1:
243 {
244 double eps = std::atan2(b(2), b(1));
245 transform(7, 0.5 * eps, R, invR);
246 break;
247 }
248 case 2:
249 {
250 double eps = - std::atan2(b(0), b(1));
251 transform(9, 0.5 * eps, R, invR);
252 break;
253 }
254 case 3:
255 {
256 double eps = - std::atanh(mr / b(1));
257 transform(2, 0.5 * eps, R, invR);
258 break;
259 }
260 case 4:
261 {
262 double eps = 0.5 * std::atan2(2.0 * mb,
263 boost::numeric::ublas::inner_prod(E, E) -
264 boost::numeric::ublas::inner_prod(P, P));
265 transform(0, 0.5 * eps, R, invR);
266 break;
267 }
268 case 5:
269 {
270 double eps = - std::atan2(P(2), P(0));
271 transform(8, 0.5 * eps, R, invR);
272 break;
273 }
274 default:
275 {
276 throw OpalException("RealDiracMatrix::update()",
277 "Case " + std::to_string(i) +
278 " not available.");
279 }
280 }
281}
Tps< T > cos(const Tps< T > &x)
Cosine.
Definition: TpsMath.h:129
Tps< T > cosh(const Tps< T > &x)
Hyperbolic cosine.
Definition: TpsMath.h:222
Tps< T > sinh(const Tps< T > &x)
Hyperbolic sine.
Definition: TpsMath.h:204
Tps< T > sin(const Tps< T > &x)
Sine.
Definition: TpsMath.h:111
T::PETE_Expr_t::PETE_Return_t prod(const PETE_Expr< T > &expr)
Definition: PETE.h:1121
PETE_TUTree< FnFabs, typename T::PETE_Expr_t > fabs(const PETE_Expr< T > &l)
Definition: PETE.h:732
PETE_TBTree< FnArcTan2, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > atan2(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
BOOST_UBLAS_INLINE ublas::vector< V, A > cross_prod(ublas::vector< V, A > &v1, ublas::vector< V, A > &v2)
Computes the cross product of two vectors in .
BOOST_UBLAS_INLINE V trace(ublas::matrix< V > &e)
Computes the trace of a square matrix.
boost::numeric::ublas::compressed_matrix< double, boost::numeric::ublas::row_major > sparse_matrix_t
Sparse matrix type definition.
RealDiracMatrix()
Default constructor (sets only NumOfRDMs and DimOfRDMs)
void transform(matrix_t &, short, double, sparse_matrix_t &, sparse_matrix_t &)
matrix_t symplex(const matrix_t &)
boost::numeric::ublas::matrix< double > matrix_t
Dense matrix type definition.
boost::numeric::ublas::vector< double, std::vector< double > > vector_t
Dense vector type definition.
sparse_matrix_t getRDM(short)
void update(matrix_t &sigma, short i, sparse_matrix_t &R, sparse_matrix_t &invR)
void diagonalize(matrix_t &, sparse_matrix_t &, sparse_matrix_t &)
The base class for all OPAL exceptions.
Definition: OpalException.h:28