OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
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 
178 void 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 
194 void 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
PETE_TBTree< FnArcTan2, PETE_Scalar< Vektor< T1, Dim > >, typename T2::PETE_Expr_t > atan2(const Vektor< T1, Dim > &l, const PETE_Expr< T2 > &r)
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
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