From 300001666184e5e329752c979072e431c7720d0f Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Thu, 12 Sep 2024 19:14:32 -0700 Subject: [PATCH 01/54] Add eigenemittance calculation. --- src/particles/diagnostics/CMakeLists.txt | 1 + .../diagnostics/CovarianceMatrixMath.H | 158 ++++++++++++++++++ .../diagnostics/EmittanceInvariants.H | 61 +++++++ .../diagnostics/EmittanceInvariants.cpp | 135 +++++++++++++++ 4 files changed, 355 insertions(+) create mode 100644 src/particles/diagnostics/CovarianceMatrixMath.H create mode 100644 src/particles/diagnostics/EmittanceInvariants.H create mode 100644 src/particles/diagnostics/EmittanceInvariants.cpp diff --git a/src/particles/diagnostics/CMakeLists.txt b/src/particles/diagnostics/CMakeLists.txt index 1ff032aad..50ad97560 100644 --- a/src/particles/diagnostics/CMakeLists.txt +++ b/src/particles/diagnostics/CMakeLists.txt @@ -2,4 +2,5 @@ target_sources(lib PRIVATE ReducedBeamCharacteristics.cpp DiagnosticOutput.cpp + EmittanceInvariants.cpp ) diff --git a/src/particles/diagnostics/CovarianceMatrixMath.H b/src/particles/diagnostics/CovarianceMatrixMath.H new file mode 100644 index 000000000..4fec87eb0 --- /dev/null +++ b/src/particles/diagnostics/CovarianceMatrixMath.H @@ -0,0 +1,158 @@ +/* Copyright 2022-2023 The Regents of the University of California, through Lawrence + * Berkeley National Laboratory (subject to receipt of any required + * approvals from the U.S. Dept. of Energy). All rights reserved. + * + * This file is part of ImpactX. + * + * Authors: Chad Mitchell, Axel Huebl + * License: BSD-3-Clause-LBNL + */ +#ifndef COVARIANCE_MATRIX_MATH_H +#define COVARIANCE_MATRIX_MATH_H + +#include +#include +#include +#include + +namespace impactx::diagnostics +{ + + /** Function to return the roots of a cubic polynomial ax^3 + bx^2 + cx + d. + * The trigonometric form of Cardano's formula is used. + * This implementation expects three real roots, which is verified + * by checking the sign of the discriminant. + * + * @param[in] coefficient a + * @param[in] coefficient b + * @param[in] coefficient c + * @param[in] coefficient d + * @returns tuple of three real roots + */ + std::tuple< + amrex::ParticleReal, + amrex::ParticleReal, + amrex::ParticleReal> + CubicRoots ( + amrex::ParticleReal a, + amrex::ParticleReal b, + amrex::ParticleReal c, + amrex::ParticleReal d + ) + { + using namespace amrex::literals; + using ablastr::constant::math::pi; + + std::tuple roots; + + amrex::ParticleReal Q = (3.0_prt*a*c - pow(b,2))/(9.0_prt * pow(a,2)); + amrex::ParticleReal R = (9.0_prt*a*b*c - 27_prt*pow(a,2)*d - 2.0_prt*pow(b,3))/(54.0_prt*pow(a,3)); + amrex::ParticleReal discriminant = pow(Q,3) + pow(R,2); + + amrex::ParticleReal theta = 0.0_prt; + + // Discriminant should be < 0. Otherwise, keep theta at default and throw an error. + if(discriminant > 0.0_prt){ + std::cout << "Polynomial in CubicRoots has one or more complex roots." << "\n"; + } else { + theta = acos(R/sqrt(-pow(Q,3))); + } + + //Three real roots in trigonometric form. + amrex::ParticleReal x1 = 2.0_prt*sqrt(-Q)*cos(theta/3.0_prt) - b/(3.0_prt*a); + amrex::ParticleReal x2 = 2.0_prt*sqrt(-Q)*cos(theta/3.0_prt + 2.0_prt*pi/3.0_prt) - b/(3.0_prt*a); + amrex::ParticleReal x3 = 2.0_prt*sqrt(-Q)*cos(theta/3.0_prt + 4.0_prt*pi/3.0_prt) - b/(3.0_prt*a); + + std::cout << "Discriminant, Q, R " << discriminant << " " << Q << " " << R << "\n"; + std::cout << "Return x1, x2, x3 " << x1 << " " << x2 << " " << x3 << "\n"; + + roots = std::make_tuple(x1,x2,x3); + return roots; + } + + + /** Function to take the trace of a square 6x6 matrix. + * + * @param[in] matrix A + * @returns the trace of A + */ + amrex::ParticleReal + TraceMat ( + amrex::Array2D A + ) + { + int const dim = 6; + amrex::ParticleReal trA = 0.0; + + for (int i = 1; i < dim+1; i++) { + trA += A(i,i); + } + return trA; + } + + + /** Function to multiply two square matrices of dimension 6. + * + * @param[in] matrix A + * @param[in] matrix B + * @returns matrix C = AB + */ + amrex::Array2D + MultiplyMat ( + amrex::Array2D A, + amrex::Array2D B + ) + { + amrex::Array2D C; + int const dim = 6; + + for (int i = 1; i < dim+1; i++) { + for (int j = 1; j < dim+1; j++) { + C(i,j) = 0; + + for (int k = 1; k < dim+1; k++) { + C(i,j) += A(i,k) * B(k,j); + } + + } + + } + return C; + } + + + void TestMult () + { + amrex::Array2D A; + amrex::Array2D B; + amrex::Array2D C; + + for (int i = 1; i < 7; i++) { + for (int j = 1; j < 7; j++) { + A(i,j) = 0; + B(i,j) = 0; + C(i,j) = 0; + } + } + for (int i = 1; i < 7; i++) { + A(i,i) = 1.0; + B(i,i) = 1.0; + } + A(2,3) = -0.3; + B(4,5) = 0.5; + C = MultiplyMat(A,B); + std::cout << "Matrix multiplication gives " << "\n"; + for (int i = 1; i < 7; i++) { + for (int j = 1; j < 7; j++) { + std::cout << i << " " << j << " " << C(i,j) << "\n"; + } + } + + + } + + + +} // namespace impactx::diagnostics + +#endif // COVARIANCE_MATRIX_MATH_H diff --git a/src/particles/diagnostics/EmittanceInvariants.H b/src/particles/diagnostics/EmittanceInvariants.H new file mode 100644 index 000000000..3a8c2c368 --- /dev/null +++ b/src/particles/diagnostics/EmittanceInvariants.H @@ -0,0 +1,61 @@ +/* Copyright 2022-2023 The Regents of the University of California, through Lawrence + * Berkeley National Laboratory (subject to receipt of any required + * approvals from the U.S. Dept. of Energy). All rights reserved. + * + * This file is part of ImpactX. + * + * Authors: Marco Garten, Chad Mitchell, Axel Huebl + * License: BSD-3-Clause-LBNL + */ +#ifndef IMPACTX_EMITTANCE_INVARIANTS +#define IMPACTX_EMITTANCE_INVARIANTS + +#include "particles/ImpactXParticleContainer.H" + +#include + +#include +#include + + +namespace impactx::diagnostics +{ + + /** Returns the three independent kinetic invariants + * denoted I2, I4, and I6 as constructed from the 6x6 + * beam covariance matrix. These three quantities are invariant + * under any linear symplectic transport map, and are used in the + * calculation of the three eigenemittances. + * + * @param[in] symmetric 6x6 covariance matrix + * @returns tuple containing I2, I4, and I6 + */ + std::tuple< + amrex::ParticleReal, + amrex::ParticleReal, + amrex::ParticleReal> + KineticInvariants ( + amrex::Array2D Sigma + ); + + /** Returns the three eigenemittances + * denoted e1, e2, and e3 as constructed from the 6x6 + * beam covariance matrix. These three quantities are invariant + * under any linear symplectic transport map, and reduce to + * the projected normalized rms emittances in the limit of + * uncoupled transport. + * + * @param[in] symmetric 6x6 covariance matrix + * @returns tuple containing e1, e2, and e3 + */ + std::tuple< + amrex::ParticleReal, + amrex::ParticleReal, + amrex::ParticleReal> + Eigenemittances ( + amrex::Array2D Sigma + ); + +} // namespace impactx::diagnostics + +#endif // IMPACTX_EMITTANCE_INVARIANTS diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp new file mode 100644 index 000000000..3f6db3725 --- /dev/null +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -0,0 +1,135 @@ +/* Copyright 2022-2023 The Regents of the University of California, through Lawrence + * Berkeley National Laboratory (subject to receipt of any required + * approvals from the U.S. Dept. of Energy). All rights reserved. + * + * This file is part of ImpactX. + * + * Authors: Chad Mitchell, Axel Huebl + * License: BSD-3-Clause-LBNL + */ +#include "CovarianceMatrixMath.H" + +#include +#include +#include +#include +#include +#include +#include + + +namespace impactx::diagnostics +{ + + /** This function returns the three independent kinetic invariants + * denoted I2, I4, and I6 as constructed from the 6x6 + * beam covariance matrix. These three quantities are invariant + * under any linear symplectic transport map, and are used in the + * calculation of the three eigenemittances. + * + * @param[in] symmetric 6x6 covariance matrix + * @returns tuple containing I2, I4, and I6 + */ + std::tuple< + amrex::ParticleReal, + amrex::ParticleReal, + amrex::ParticleReal> + KineticInvariants ( + amrex::Array2D Sigma + ) + { + using namespace amrex::literals; + + std::tuple invariants; + amrex::ParticleReal I2 = 0.0_prt; + amrex::ParticleReal I4 = 0.0_prt; + amrex::ParticleReal I6 = 0.0_prt; + + // Intermediate matrices used for storage. + amrex::Array2D S1; + amrex::Array2D S2; + amrex::Array2D S4; + amrex::Array2D S6; + + // Construct the matrix S1 = Sigma*J. This is a + // permutation of the columns of Sigma with + // a change of sign. + for (int i = 1; i < 7; i++) { + for (int j = 1; j < 7; j++) { + if (j % 2) { + S1(i,j) = -Sigma(i,j+1); // if j is odd + } + else { + S1(i,j) = +Sigma(i,j-1); // if j is even + } + } + } + + // Carry out necessary matrix multiplications (3 are needed). + S2 = impactx::diagnostics::MultiplyMat(S1,S1); + S4 = impactx::diagnostics::MultiplyMat(S2,S2); + S6 = impactx::diagnostics::MultiplyMat(S2,S4); + + // Define the three kinematic invariants (should be nonnegative). + I2 = -impactx::diagnostics::TraceMat(S2)/2.0_prt; + I4 = +impactx::diagnostics::TraceMat(S4)/2.0_prt; + I6 = -impactx::diagnostics::TraceMat(S6)/2.0_prt; + + std::cout << "Return I2, I4, I6 " << I2 << " " << I4 << " " << I6 << "\n"; + + invariants = std::make_tuple(I2,I4,I6); + return invariants; + } + + + /** This function returns the three eigenemittances + * denoted e1, e2, and e3 as constructed from the 6x6 + * beam covariance matrix. These three quantities are invariant + * under any linear symplectic transport map, and reduce to + * the projected normalized rms emittances in the limit of + * uncoupled transport. + * + * @param[in] symmetric 6x6 covariance matrix + * @returns tuple containing e1, e2, and e3 + */ + std::tuple< + amrex::ParticleReal, + amrex::ParticleReal, + amrex::ParticleReal> + Eigenemittances ( + amrex::Array2D Sigma + ) + { + using namespace amrex::literals; + + std::tuple invariants; + std::tuple roots; + std::tuple emittances; + + // Get the invariants I2, I4, and I6 from the covariance matrix. + invariants = KineticInvariants(Sigma); + amrex::ParticleReal I2 = std::get<0>(invariants); + amrex::ParticleReal I4 = std::get<1>(invariants); + amrex::ParticleReal I6 = std::get<2>(invariants); + + // Construct the coefficients of the cubic polynomial + amrex::ParticleReal a = 1.0_prt; + amrex::ParticleReal b = -I2; + amrex::ParticleReal c = (pow(I2,2)-I4)/2.0_prt; + amrex::ParticleReal d = -pow(I2,3)/6.0_prt + I2*I4/2.0_prt - I6/3.0_prt; + + // Return the cubic coefficients + std::cout << "Return a,b,c,d " << a << " " << b << " " << c << " " << d << "\n"; + + // Solve for the roots to obtain the eigenemittances. + roots = CubicRoots(a,b,c,d); + amrex::ParticleReal e1 = sqrt(std::get<0>(roots)); + amrex::ParticleReal e2 = sqrt(std::get<1>(roots)); + amrex::ParticleReal e3 = sqrt(std::get<2>(roots)); + + emittances = std::make_tuple(e1,e2,e3); + return emittances; + } + + +} // namespace impactx::diagnostics From 9584c62105db4c672c95e3f373ef0cb38daf0546 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2024 02:22:40 +0000 Subject: [PATCH 02/54] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/particles/diagnostics/CovarianceMatrixMath.H | 14 +++++++------- src/particles/diagnostics/EmittanceInvariants.cpp | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/particles/diagnostics/CovarianceMatrixMath.H b/src/particles/diagnostics/CovarianceMatrixMath.H index 4fec87eb0..2e832874e 100644 --- a/src/particles/diagnostics/CovarianceMatrixMath.H +++ b/src/particles/diagnostics/CovarianceMatrixMath.H @@ -52,7 +52,7 @@ namespace impactx::diagnostics amrex::ParticleReal theta = 0.0_prt; // Discriminant should be < 0. Otherwise, keep theta at default and throw an error. - if(discriminant > 0.0_prt){ + if(discriminant > 0.0_prt){ std::cout << "Polynomial in CubicRoots has one or more complex roots." << "\n"; } else { theta = acos(R/sqrt(-pow(Q,3))); @@ -66,13 +66,13 @@ namespace impactx::diagnostics std::cout << "Discriminant, Q, R " << discriminant << " " << Q << " " << R << "\n"; std::cout << "Return x1, x2, x3 " << x1 << " " << x2 << " " << x3 << "\n"; - roots = std::make_tuple(x1,x2,x3); + roots = std::make_tuple(x1,x2,x3); return roots; } /** Function to take the trace of a square 6x6 matrix. - * + * * @param[in] matrix A * @returns the trace of A */ @@ -81,11 +81,11 @@ namespace impactx::diagnostics amrex::Array2D A ) { - int const dim = 6; + int const dim = 6; amrex::ParticleReal trA = 0.0; for (int i = 1; i < dim+1; i++) { - trA += A(i,i); + trA += A(i,i); } return trA; } @@ -115,9 +115,9 @@ namespace impactx::diagnostics } } - + } - return C; + return C; } diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index 3f6db3725..831a8b39f 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -22,7 +22,7 @@ namespace impactx::diagnostics { /** This function returns the three independent kinetic invariants - * denoted I2, I4, and I6 as constructed from the 6x6 + * denoted I2, I4, and I6 as constructed from the 6x6 * beam covariance matrix. These three quantities are invariant * under any linear symplectic transport map, and are used in the * calculation of the three eigenemittances. @@ -51,8 +51,8 @@ namespace impactx::diagnostics amrex::Array2D S4; amrex::Array2D S6; - // Construct the matrix S1 = Sigma*J. This is a - // permutation of the columns of Sigma with + // Construct the matrix S1 = Sigma*J. This is a + // permutation of the columns of Sigma with // a change of sign. for (int i = 1; i < 7; i++) { for (int j = 1; j < 7; j++) { @@ -69,7 +69,7 @@ namespace impactx::diagnostics S2 = impactx::diagnostics::MultiplyMat(S1,S1); S4 = impactx::diagnostics::MultiplyMat(S2,S2); S6 = impactx::diagnostics::MultiplyMat(S2,S4); - + // Define the three kinematic invariants (should be nonnegative). I2 = -impactx::diagnostics::TraceMat(S2)/2.0_prt; I4 = +impactx::diagnostics::TraceMat(S4)/2.0_prt; @@ -130,6 +130,6 @@ namespace impactx::diagnostics emittances = std::make_tuple(e1,e2,e3); return emittances; } - + } // namespace impactx::diagnostics From 176405a9bd69962346c8defd1aae815354f7a321 Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Fri, 13 Sep 2024 08:18:10 -0700 Subject: [PATCH 03/54] Update CovarianceMatrixMath.H Clean Doxygen and delete unused function TestMult (used for benchmarking). --- .../diagnostics/CovarianceMatrixMath.H | 48 ++++--------------- 1 file changed, 8 insertions(+), 40 deletions(-) diff --git a/src/particles/diagnostics/CovarianceMatrixMath.H b/src/particles/diagnostics/CovarianceMatrixMath.H index 2e832874e..7ca5baa18 100644 --- a/src/particles/diagnostics/CovarianceMatrixMath.H +++ b/src/particles/diagnostics/CovarianceMatrixMath.H @@ -23,10 +23,10 @@ namespace impactx::diagnostics * This implementation expects three real roots, which is verified * by checking the sign of the discriminant. * - * @param[in] coefficient a - * @param[in] coefficient b - * @param[in] coefficient c - * @param[in] coefficient d + * @param[in] a coefficient of cubic term + * @param[in] b coefficient of quadratic term + * @param[in] c coefficient of linear term + * @param[in] d coefficient of constant term * @returns tuple of three real roots */ std::tuple< @@ -73,7 +73,7 @@ namespace impactx::diagnostics /** Function to take the trace of a square 6x6 matrix. * - * @param[in] matrix A + * @param[in] A a square matrix * @returns the trace of A */ amrex::ParticleReal @@ -93,9 +93,9 @@ namespace impactx::diagnostics /** Function to multiply two square matrices of dimension 6. * - * @param[in] matrix A - * @param[in] matrix B - * @returns matrix C = AB + * @param[in] A a square matrix + * @param[in] B square matrix + * @returns the matrix C = AB */ amrex::Array2D MultiplyMat ( @@ -121,38 +121,6 @@ namespace impactx::diagnostics } - void TestMult () - { - amrex::Array2D A; - amrex::Array2D B; - amrex::Array2D C; - - for (int i = 1; i < 7; i++) { - for (int j = 1; j < 7; j++) { - A(i,j) = 0; - B(i,j) = 0; - C(i,j) = 0; - } - } - for (int i = 1; i < 7; i++) { - A(i,i) = 1.0; - B(i,i) = 1.0; - } - A(2,3) = -0.3; - B(4,5) = 0.5; - C = MultiplyMat(A,B); - std::cout << "Matrix multiplication gives " << "\n"; - for (int i = 1; i < 7; i++) { - for (int j = 1; j < 7; j++) { - std::cout << i << " " << j << " " << C(i,j) << "\n"; - } - } - - - } - - - } // namespace impactx::diagnostics #endif // COVARIANCE_MATRIX_MATH_H From b51293bf75243f2f75e513f25b2757b72a62adca Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Fri, 13 Sep 2024 08:20:11 -0700 Subject: [PATCH 04/54] Update EmittanceInvariants.cpp Clean Doxygen --- src/particles/diagnostics/EmittanceInvariants.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index 831a8b39f..bcf8e55c2 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -27,8 +27,8 @@ namespace impactx::diagnostics * under any linear symplectic transport map, and are used in the * calculation of the three eigenemittances. * - * @param[in] symmetric 6x6 covariance matrix - * @returns tuple containing I2, I4, and I6 + * @param[in] Sigma symmetric 6x6 covariance matrix + * @returns tuple containing invarants I2, I4, and I6 */ std::tuple< amrex::ParticleReal, @@ -89,8 +89,8 @@ namespace impactx::diagnostics * the projected normalized rms emittances in the limit of * uncoupled transport. * - * @param[in] symmetric 6x6 covariance matrix - * @returns tuple containing e1, e2, and e3 + * @param[in] Sigma symmetric 6x6 covariance matrix + * @returns tuple containing eigenemittances e1, e2, and e3 */ std::tuple< amrex::ParticleReal, From 6b1e91135f5aa226734cd7e1a1e4ef2478e0befc Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Fri, 13 Sep 2024 08:22:56 -0700 Subject: [PATCH 05/54] Update EmittanceInvariants.H Clean Doxygen --- src/particles/diagnostics/EmittanceInvariants.H | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/particles/diagnostics/EmittanceInvariants.H b/src/particles/diagnostics/EmittanceInvariants.H index 3a8c2c368..90fb21618 100644 --- a/src/particles/diagnostics/EmittanceInvariants.H +++ b/src/particles/diagnostics/EmittanceInvariants.H @@ -27,8 +27,8 @@ namespace impactx::diagnostics * under any linear symplectic transport map, and are used in the * calculation of the three eigenemittances. * - * @param[in] symmetric 6x6 covariance matrix - * @returns tuple containing I2, I4, and I6 + * @param[in] Sigma symmetric 6x6 covariance matrix + * @returns tuple containing invariants I2, I4, and I6 */ std::tuple< amrex::ParticleReal, @@ -45,8 +45,8 @@ namespace impactx::diagnostics * the projected normalized rms emittances in the limit of * uncoupled transport. * - * @param[in] symmetric 6x6 covariance matrix - * @returns tuple containing e1, e2, and e3 + * @param[in] Sigma symmetric 6x6 covariance matrix + * @returns tuple containing eigenemittances e1, e2, and e3 */ std::tuple< amrex::ParticleReal, From 4b3fdd1e60641660f84cca947eef555a1186278c Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Fri, 13 Sep 2024 08:27:56 -0700 Subject: [PATCH 06/54] Update EmittanceInvariants.cpp Remove duplicate Doxygen comments in EmittanceInvariants.cpp/h --- src/particles/diagnostics/EmittanceInvariants.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index bcf8e55c2..8be068cdd 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -27,8 +27,8 @@ namespace impactx::diagnostics * under any linear symplectic transport map, and are used in the * calculation of the three eigenemittances. * - * @param[in] Sigma symmetric 6x6 covariance matrix - * @returns tuple containing invarants I2, I4, and I6 + * input - Sigma symmetric 6x6 covariance matrix + * returns - tuple containing invarants I2, I4, and I6 */ std::tuple< amrex::ParticleReal, @@ -89,8 +89,8 @@ namespace impactx::diagnostics * the projected normalized rms emittances in the limit of * uncoupled transport. * - * @param[in] Sigma symmetric 6x6 covariance matrix - * @returns tuple containing eigenemittances e1, e2, and e3 + * input - Sigma symmetric 6x6 covariance matrix + * returns - tuple containing eigenemittances e1, e2, and e3 */ std::tuple< amrex::ParticleReal, From 62a11c5a4d2b09e0797ebe600dfce0283014823e Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Fri, 13 Sep 2024 10:09:50 -0700 Subject: [PATCH 07/54] Treat special case of vanishing discriminant in Cardano's formula. --- .../diagnostics/CovarianceMatrixMath.H | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/particles/diagnostics/CovarianceMatrixMath.H b/src/particles/diagnostics/CovarianceMatrixMath.H index 7ca5baa18..2a812280c 100644 --- a/src/particles/diagnostics/CovarianceMatrixMath.H +++ b/src/particles/diagnostics/CovarianceMatrixMath.H @@ -44,24 +44,35 @@ namespace impactx::diagnostics using ablastr::constant::math::pi; std::tuple roots; + amrex::ParticleReal x1 = 0.0_prt; + amrex::ParticleReal x2 = 0.0_prt; + amrex::ParticleReal x3 = 0.0_prt; amrex::ParticleReal Q = (3.0_prt*a*c - pow(b,2))/(9.0_prt * pow(a,2)); amrex::ParticleReal R = (9.0_prt*a*b*c - 27_prt*pow(a,2)*d - 2.0_prt*pow(b,3))/(54.0_prt*pow(a,3)); amrex::ParticleReal discriminant = pow(Q,3) + pow(R,2); - amrex::ParticleReal theta = 0.0_prt; - // Discriminant should be < 0. Otherwise, keep theta at default and throw an error. - if(discriminant > 0.0_prt){ + amrex::ParticleReal tol = 1.0e-12; //allow for roundoff error + if(discriminant > tol){ + std::cout << "Polynomial in CubicRoots has one or more complex roots." << "\n"; + + } else if (Q == 0.0_prt){ // Special case of a triple root + + x1 = - b/(3.0_prt*a); + x2 = - b/(3.0_prt*a); + x3 = - b/(3.0_prt*a); + } else { - theta = acos(R/sqrt(-pow(Q,3))); - } - //Three real roots in trigonometric form. - amrex::ParticleReal x1 = 2.0_prt*sqrt(-Q)*cos(theta/3.0_prt) - b/(3.0_prt*a); - amrex::ParticleReal x2 = 2.0_prt*sqrt(-Q)*cos(theta/3.0_prt + 2.0_prt*pi/3.0_prt) - b/(3.0_prt*a); - amrex::ParticleReal x3 = 2.0_prt*sqrt(-Q)*cos(theta/3.0_prt + 4.0_prt*pi/3.0_prt) - b/(3.0_prt*a); + //Three real roots in trigonometric form. + amrex::ParticleReal theta = acos(R/sqrt(-pow(Q,3))); + x1 = 2.0_prt*sqrt(-Q)*cos(theta/3.0_prt) - b/(3.0_prt*a); + x2 = 2.0_prt*sqrt(-Q)*cos(theta/3.0_prt + 2.0_prt*pi/3.0_prt) - b/(3.0_prt*a); + x3 = 2.0_prt*sqrt(-Q)*cos(theta/3.0_prt + 4.0_prt*pi/3.0_prt) - b/(3.0_prt*a); + + } std::cout << "Discriminant, Q, R " << discriminant << " " << Q << " " << R << "\n"; std::cout << "Return x1, x2, x3 " << x1 << " " << x2 << " " << x3 << "\n"; From 55ec468c36b3abbda76c1b8a967d0bd8005bac9a Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Fri, 13 Sep 2024 11:27:22 -0700 Subject: [PATCH 08/54] Test from ReducedDiagnostics; update ej ordering. --- .../diagnostics/EmittanceInvariants.cpp | 9 +++-- .../ReducedBeamCharacteristics.cpp | 34 +++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index 8be068cdd..d3eb6dd02 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -123,10 +123,13 @@ namespace impactx::diagnostics // Solve for the roots to obtain the eigenemittances. roots = CubicRoots(a,b,c,d); - amrex::ParticleReal e1 = sqrt(std::get<0>(roots)); - amrex::ParticleReal e2 = sqrt(std::get<1>(roots)); - amrex::ParticleReal e3 = sqrt(std::get<2>(roots)); + amrex::ParticleReal e1 = sqrt(std::get<1>(roots)); + amrex::ParticleReal e2 = sqrt(std::get<2>(roots)); + amrex::ParticleReal e3 = sqrt(std::get<0>(roots)); + // Caution: The order of e1,e2,e3 should be consistent with the + // order ex,ey,et in the limit of uncoupled transport. The + // ordering remains to be carefully checked (TODO). emittances = std::make_tuple(e1,e2,e3); return emittances; } diff --git a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp index 0b6ed024d..a7433ee26 100644 --- a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp +++ b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp @@ -12,6 +12,7 @@ #include "particles/ImpactXParticleContainer.H" #include "particles/ReferenceParticle.H" +#include "EmittanceInvariants.H" #include // for TinyProfiler #include // for AMREX_GPU_DEVICE @@ -323,6 +324,39 @@ namespace impactx::diagnostics data["dispersion_py"] = dispersion_py; data["charge_C"] = charge; + // The following lines are added temporarily, for the sole + // purpose of benchmarking the eigenemittance output for + // a given beam covariance matrix Sigma. + amrex::Array2D Sigma; + for (int i = 1; i < 7; i++) { + for (int j = 1; j < 7; j++) { + Sigma(i,j) = 0.0; + } + } + for (int i = 1; i<7; i++) { + Sigma(i,i) = 1.0; + } + Sigma(1,1) = 3.0; + Sigma(1,2) = 2.0; + Sigma(2,1) = 2.0; + Sigma(2,2) = 3.0; + + Sigma(3,3) = 1.0; + Sigma(3,4) = 0.5; + Sigma(4,3) = 0.5; + Sigma(4,4) = 1.0; + + Sigma(5,5) = 4.0; + Sigma(5,6) = 1.0; + Sigma(6,5) = 1.0; + Sigma(6,6) = 4.0; + + Sigma(1,6) = 1.0; + Sigma(6,1) = 1.0; + + std::tuple emittances = Eigenemittances(Sigma); + std::cout << "Emittances = " << std::get<0>(emittances) << " " << std::get<1>(emittances) << " " << std::get<2>(emittances); + return data; } } // namespace impactx::diagnostics From ecde5323798f6002a0fa3f67a8afe67dcb65c207 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2024 18:28:39 +0000 Subject: [PATCH 09/54] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/particles/diagnostics/EmittanceInvariants.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index d3eb6dd02..57504df97 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -129,7 +129,7 @@ namespace impactx::diagnostics // Caution: The order of e1,e2,e3 should be consistent with the // order ex,ey,et in the limit of uncoupled transport. The - // ordering remains to be carefully checked (TODO). + // ordering remains to be carefully checked (TODO). emittances = std::make_tuple(e1,e2,e3); return emittances; } From 8f22292c50bb0be7c51ab6de34b47ef7230a6cd8 Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Fri, 13 Sep 2024 14:21:07 -0700 Subject: [PATCH 10/54] Add diagnostic output. --- .../ReducedBeamCharacteristics.cpp | 80 +++++++++++++++++-- 1 file changed, 75 insertions(+), 5 deletions(-) diff --git a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp index a7433ee26..d598b13d2 100644 --- a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp +++ b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp @@ -152,7 +152,7 @@ namespace impactx::diagnostics * https://stackoverflow.com/questions/55136414/constexpr-variable-captured-inside-lambda-loses-its-constexpr-ness */ // number of reduction operations in second concurrent batch - static constexpr std::size_t num_red_ops_2 = 14; + static constexpr std::size_t num_red_ops_2 = 22; // prepare reduction operations for calculation of mean square and correlation values amrex::TypeMultiplier reduce_ops_2; using ReducedDataT2 = amrex::TypeMultiplier; @@ -183,12 +183,20 @@ namespace impactx::diagnostics const amrex::ParticleReal p_xpx = (p_x-x_mean)*(p_px-px_mean)*p_w; const amrex::ParticleReal p_ypy = (p_y-y_mean)*(p_py-py_mean)*p_w; const amrex::ParticleReal p_tpt = (p_t-t_mean)*(p_pt-pt_mean)*p_w; - // prepare correlations for dispersion + // prepare correlations for dispersion (4 required) const amrex::ParticleReal p_xpt = (p_x-x_mean)*(p_pt-pt_mean)*p_w; const amrex::ParticleReal p_pxpt = (p_px-px_mean)*(p_pt-pt_mean)*p_w; const amrex::ParticleReal p_ypt = (p_y-y_mean)*(p_pt-pt_mean)*p_w; const amrex::ParticleReal p_pypt = (p_py-py_mean)*(p_pt-pt_mean)*p_w; - + // prepare additional cross-plane correlations (8 required) + const amrex::ParticleReal p_xy = (p_x-x_mean)*(p_y-y_mean)*p_w; + const amrex::ParticleReal p_xpy = (p_x-x_mean)*(p_py-py_mean)*p_w; + const amrex::ParticleReal p_xt = (p_x-x_mean)*(p_t-t_mean)*p_w; + const amrex::ParticleReal p_pxy = (p_px-px_mean)*(p_y-y_mean)*p_w; + const amrex::ParticleReal p_pxpy = (p_px-px_mean)*(p_py-py_mean)*p_w; + const amrex::ParticleReal p_pxt = (p_px-px_mean)*(p_t-t_mean)*p_w; + const amrex::ParticleReal p_yt = (p_y-y_mean)*(p_t-t_mean)*p_w; + const amrex::ParticleReal p_pyt = (p_py-py_mean)*(p_t-t_mean)*p_w; const amrex::ParticleReal p_charge = q_C*p_w; @@ -196,6 +204,7 @@ namespace impactx::diagnostics p_px_ms, p_py_ms, p_pt_ms, p_xpx, p_ypy, p_tpt, p_xpt, p_pxpt, p_ypt, p_pypt, + p_xy, p_xpy, p_xt, p_pxy, p_pxpy, p_pxt, p_yt, p_pyt, p_charge}; }, reduce_ops_2 @@ -208,6 +217,7 @@ namespace impactx::diagnostics * px_ms, py_ms, pt_ms, * xpx, ypy, tpt, * p_xpt, p_pxpt, p_ypt, p_pypt, + * p_xy, p_xpy, p_xt, p_pxy, p_pxpy, p_pxt, p_yt, p_pyt, * charge */ amrex::constexpr_for<0, num_red_ops_2> ([&](auto i) { @@ -249,7 +259,15 @@ namespace impactx::diagnostics amrex::ParticleReal const pxpt = values_per_rank_2nd.at(10) /= w_sum; amrex::ParticleReal const ypt = values_per_rank_2nd.at(11) /= w_sum; amrex::ParticleReal const pypt = values_per_rank_2nd.at(12) /= w_sum; - amrex::ParticleReal const charge = values_per_rank_2nd.at(13); + amrex::ParticleReal const xy = values_per_rank_2nd.at(13) /= w_sum; + amrex::ParticleReal const xpy = values_per_rank_2nd.at(14) /= w_sum; + amrex::ParticleReal const xt = values_per_rank_2nd.at(15) /= w_sum; + amrex::ParticleReal const pxy = values_per_rank_2nd.at(16) /= w_sum; + amrex::ParticleReal const pxpy = values_per_rank_2nd.at(17) /= w_sum; + amrex::ParticleReal const pxt = values_per_rank_2nd.at(18) /= w_sum; + amrex::ParticleReal const yt = values_per_rank_2nd.at(19) /= w_sum; + amrex::ParticleReal const pyt = values_per_rank_2nd.at(20) /= w_sum; + amrex::ParticleReal const charge = values_per_rank_2nd.at(21); // standard deviations of positions amrex::ParticleReal const sig_x = std::sqrt(x_ms); amrex::ParticleReal const sig_y = std::sqrt(y_ms); @@ -284,6 +302,55 @@ namespace impactx::diagnostics amrex::ParticleReal const alpha_y = - ypy_d / emittance_yd; amrex::ParticleReal const alpha_t = - tpt / emittance_t; + // Calculate eigenemittances (optional) + amrex::Array2D Sigma; + amrex::ParticleReal emittance_1 = emittance_x; + amrex::ParticleReal emittance_2 = emittance_y; + amrex::ParticleReal emittance_3 = emittance_t; + bool compute_eigenemittances = true; + if (compute_eigenemittances) { + Sigma(1,1) = x_ms; + Sigma(1,2) = xpx; + Sigma(1,3) = xy; + Sigma(1,4) = xpy; + Sigma(1,5) = xt; + Sigma(1,6) = xpt; + Sigma(2,1) = xpx; + Sigma(2,2) = px_ms; + Sigma(2,3) = pxy; + Sigma(2,4) = pxpy; + Sigma(2,5) = pxt; + Sigma(2,6) = pxpt; + Sigma(3,1) = xy; + Sigma(3,2) = pxy; + Sigma(3,3) = y_ms; + Sigma(3,4) = ypy; + Sigma(3,5) = yt; + Sigma(3,6) = ypt; + Sigma(4,1) = xpy; + Sigma(4,2) = pxpy; + Sigma(4,3) = ypy; + Sigma(4,4) = py_ms; + Sigma(4,5) = pyt; + Sigma(4,6) = pypt; + Sigma(5,1) = xt; + Sigma(5,2) = pxt; + Sigma(5,3) = yt; + Sigma(5,4) = pyt; + Sigma(5,5) = t_ms; + Sigma(5,6) = tpt; + Sigma(6,1) = xpt; + Sigma(6,2) = pxpt; + Sigma(6,3) = ypt; + Sigma(6,4) = pypt; + Sigma(6,5) = tpt; + Sigma(6,6) = pt_ms; + std::tuple emittances = Eigenemittances(Sigma); + emittance_1 = std::get<0>(emittances); + emittance_2 = std::get<1>(emittances); + emittance_3 = std::get<2>(emittances); + } + std::unordered_map data; data["x_mean"] = x_mean; data["x_min"] = x_min; @@ -323,11 +390,14 @@ namespace impactx::diagnostics data["dispersion_y"] = dispersion_y; data["dispersion_py"] = dispersion_py; data["charge_C"] = charge; + data["emittance_1"] = emittance_1; + data["emittance_2"] = emittance_2; + data["emittance_3"] = emittance_3; // The following lines are added temporarily, for the sole // purpose of benchmarking the eigenemittance output for // a given beam covariance matrix Sigma. - amrex::Array2D Sigma; + //amrex::Array2D Sigma; for (int i = 1; i < 7; i++) { for (int j = 1; j < 7; j++) { Sigma(i,j) = 0.0; From 2297ae50730d5c35f520fe6201652d16107f94b5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2024 21:21:39 +0000 Subject: [PATCH 11/54] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/particles/diagnostics/ReducedBeamCharacteristics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp index d598b13d2..9527c97ad 100644 --- a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp +++ b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp @@ -190,7 +190,7 @@ namespace impactx::diagnostics const amrex::ParticleReal p_pypt = (p_py-py_mean)*(p_pt-pt_mean)*p_w; // prepare additional cross-plane correlations (8 required) const amrex::ParticleReal p_xy = (p_x-x_mean)*(p_y-y_mean)*p_w; - const amrex::ParticleReal p_xpy = (p_x-x_mean)*(p_py-py_mean)*p_w; + const amrex::ParticleReal p_xpy = (p_x-x_mean)*(p_py-py_mean)*p_w; const amrex::ParticleReal p_xt = (p_x-x_mean)*(p_t-t_mean)*p_w; const amrex::ParticleReal p_pxy = (p_px-px_mean)*(p_y-y_mean)*p_w; const amrex::ParticleReal p_pxpy = (p_px-px_mean)*(p_py-py_mean)*p_w; From db26dde080e1ea353cb1b2111cac0ffbb0d17e4a Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Fri, 13 Sep 2024 14:57:44 -0700 Subject: [PATCH 12/54] Comment print statements used for debugging. --- src/particles/diagnostics/CovarianceMatrixMath.H | 4 ++-- src/particles/diagnostics/EmittanceInvariants.cpp | 4 ++-- src/particles/diagnostics/ReducedBeamCharacteristics.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/particles/diagnostics/CovarianceMatrixMath.H b/src/particles/diagnostics/CovarianceMatrixMath.H index 2a812280c..7e91d1274 100644 --- a/src/particles/diagnostics/CovarianceMatrixMath.H +++ b/src/particles/diagnostics/CovarianceMatrixMath.H @@ -74,8 +74,8 @@ namespace impactx::diagnostics } - std::cout << "Discriminant, Q, R " << discriminant << " " << Q << " " << R << "\n"; - std::cout << "Return x1, x2, x3 " << x1 << " " << x2 << " " << x3 << "\n"; + //std::cout << "Discriminant, Q, R " << discriminant << " " << Q << " " << R << "\n"; + //std::cout << "Return x1, x2, x3 " << x1 << " " << x2 << " " << x3 << "\n"; roots = std::make_tuple(x1,x2,x3); return roots; diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index 57504df97..ed9dfddc0 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -75,7 +75,7 @@ namespace impactx::diagnostics I4 = +impactx::diagnostics::TraceMat(S4)/2.0_prt; I6 = -impactx::diagnostics::TraceMat(S6)/2.0_prt; - std::cout << "Return I2, I4, I6 " << I2 << " " << I4 << " " << I6 << "\n"; + //std::cout << "Return I2, I4, I6 " << I2 << " " << I4 << " " << I6 << "\n"; invariants = std::make_tuple(I2,I4,I6); return invariants; @@ -119,7 +119,7 @@ namespace impactx::diagnostics amrex::ParticleReal d = -pow(I2,3)/6.0_prt + I2*I4/2.0_prt - I6/3.0_prt; // Return the cubic coefficients - std::cout << "Return a,b,c,d " << a << " " << b << " " << c << " " << d << "\n"; + //std::cout << "Return a,b,c,d " << a << " " << b << " " << c << " " << d << "\n"; // Solve for the roots to obtain the eigenemittances. roots = CubicRoots(a,b,c,d); diff --git a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp index 9527c97ad..d5c1c450c 100644 --- a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp +++ b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp @@ -425,7 +425,7 @@ namespace impactx::diagnostics Sigma(6,1) = 1.0; std::tuple emittances = Eigenemittances(Sigma); - std::cout << "Emittances = " << std::get<0>(emittances) << " " << std::get<1>(emittances) << " " << std::get<2>(emittances); + //std::cout << "Emittances = " << std::get<0>(emittances) << " " << std::get<1>(emittances) << " " << std::get<2>(emittances); return data; } From d4f0a1496933547bc6d22d7565e1a4670a0e9720 Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Fri, 13 Sep 2024 15:47:09 -0700 Subject: [PATCH 13/54] Update ReducedBeamCharacteristics.cpp Comment benchmarking call to Eigenemittance to avoid unused variable errors. --- src/particles/diagnostics/ReducedBeamCharacteristics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp index d5c1c450c..71637c404 100644 --- a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp +++ b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp @@ -424,7 +424,7 @@ namespace impactx::diagnostics Sigma(1,6) = 1.0; Sigma(6,1) = 1.0; - std::tuple emittances = Eigenemittances(Sigma); + //std::tuple emittances = Eigenemittances(Sigma); //std::cout << "Emittances = " << std::get<0>(emittances) << " " << std::get<1>(emittances) << " " << std::get<2>(emittances); return data; From 939909d81e6ca0e7e9ece7ccaf064ca5951c7a98 Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Fri, 13 Sep 2024 18:23:19 -0700 Subject: [PATCH 14/54] Add benchmark example. --- examples/coupled_optics/README.rst | 51 +++++++ .../coupled_optics/analysis_coupled_optics.py | 138 ++++++++++++++++++ .../coupled_optics/input_coupled_optics.in | 71 +++++++++ examples/coupled_optics/run_coupled_optics.py | 80 ++++++++++ 4 files changed, 340 insertions(+) create mode 100644 examples/coupled_optics/README.rst create mode 100755 examples/coupled_optics/analysis_coupled_optics.py create mode 100644 examples/coupled_optics/input_coupled_optics.in create mode 100644 examples/coupled_optics/run_coupled_optics.py diff --git a/examples/coupled_optics/README.rst b/examples/coupled_optics/README.rst new file mode 100644 index 000000000..de06da044 --- /dev/null +++ b/examples/coupled_optics/README.rst @@ -0,0 +1,51 @@ +.. _examples-coupled-optics: + +Coupled optics +================ + +This is a lattice illustrating fully coupled 6D transport. It is obtained from the example "dogleg" by adding a solenoid after the first bending dipole. +The solenoid is identical to that found in the example "solenoid". + +Its primary purpose is to benchmark the calculation of the three beam eigenemittances (mode emittances). + +In this test, the initial and final values of :math:`\lambda_x`, :math:`\lambda_y`, :math:`\lambda_t`, :math:`\epsilon_x`, :math:`\epsilon_y`, and :math:`\epsilon_t` must +agree with nominal values. + +In addition, the initial and final values of :math:`emittance_1`, :math:`emittance_2`, :math:`emittance_3` must coincide. + + +Run +--- + +This example can be run **either** as: + +* **Python** script: ``python3 run_coupled_optics.py`` or +* ImpactX **executable** using an input file: ``impactx input_coupled_optics.in`` + +For `MPI-parallel `__ runs, prefix these lines with ``mpiexec -n 4 ...`` or ``srun -n 4 ...``, depending on the system. + +.. tab-set:: + + .. tab-item:: Python: Script + + .. literalinclude:: run_coupled_optics.py + :language: python3 + :caption: You can copy this file from ``examples/coupled_optics/run_coupled_optics.py``. + + .. tab-item:: Executable: Input File + + .. literalinclude:: input_coupled_optics.in + :language: ini + :caption: You can copy this file from ``examples/coupled_optics/input_coupled_optics.in``. + + +Analyze +------- + +We run the following script to analyze correctness: + +.. dropdown:: Script ``analysis_coupled_optics.py`` + + .. literalinclude:: analysis_coupled_optics.py + :language: python3 + :caption: You can copy this file from ``examples/coupled_optics/analysis_coupled_optics.py``. diff --git a/examples/coupled_optics/analysis_coupled_optics.py b/examples/coupled_optics/analysis_coupled_optics.py new file mode 100755 index 000000000..ca6e5c7a8 --- /dev/null +++ b/examples/coupled_optics/analysis_coupled_optics.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3 +# +# Copyright 2022-2023 ImpactX contributors +# Authors: Axel Huebl, Chad Mitchell +# License: BSD-3-Clause-LBNL +# + +import numpy as np +import openpmd_api as io +from scipy.stats import moment + + +def get_moments(beam): + """Calculate standard deviations of beam position & momenta + and emittance values + + Returns + ------- + sigx, sigy, sigt, emittance_x, emittance_y, emittance_t + """ + sigx = moment(beam["position_x"], moment=2) ** 0.5 # variance -> std dev. + sigpx = moment(beam["momentum_x"], moment=2) ** 0.5 + sigy = moment(beam["position_y"], moment=2) ** 0.5 + sigpy = moment(beam["momentum_y"], moment=2) ** 0.5 + sigt = moment(beam["position_t"], moment=2) ** 0.5 + sigpt = moment(beam["momentum_t"], moment=2) ** 0.5 + + epstrms = beam.cov(ddof=0) + emittance_x = (sigx**2 * sigpx**2 - epstrms["position_x"]["momentum_x"] ** 2) ** 0.5 + emittance_y = (sigy**2 * sigpy**2 - epstrms["position_y"]["momentum_y"] ** 2) ** 0.5 + emittance_t = (sigt**2 * sigpt**2 - epstrms["position_t"]["momentum_t"] ** 2) ** 0.5 + + return (sigx, sigy, sigt, emittance_x, emittance_y, emittance_t) + + +def get_eigenemittances(openpmd_beam): + """Return eigenemittances from an openPMD particle species + + Returns + ------- + emittance_1, emittance_2, emittance_3 + """ + emittance_1 = openpmd_beam.get_attribute("emittance_1") + emittance_2 = openpmd_beam.get_attribute("emittance_2") + emittance_3 = openpmd_beam.get_attribute("emittance_3") + + return (emittance_1, emittance_2, emittance_3) + + +# initial/final beam +series = io.Series("diags/openPMD/monitor.h5", io.Access.read_only) +last_step = list(series.iterations)[-1] +initial_beam = series.iterations[1].particles["beam"] +initial = initial_beam.to_df() +final_beam = series.iterations[last_step].particles["beam"] +final = final_beam.to_df() + +# compare number of particles +num_particles = 10000 +assert num_particles == len(initial) +assert num_particles == len(final) + +print("Initial Beam:") +sigx, sigy, sigt, emittance_x, emittance_y, emittance_t = get_moments(initial) +print(f" sigx={sigx:e} sigy={sigy:e} sigt={sigt:e}") +print( + f" emittance_x={emittance_x:e} emittance_y={emittance_y:e} emittance_t={emittance_t:e}" +) + +atol = 0.0 # ignored +rtol = 2.2 * num_particles**-0.5 # from random sampling of a smooth distribution +print(f" rtol={rtol} (ignored: atol~={atol})") + +assert np.allclose( + [sigx, sigy, sigt, emittance_x, emittance_y, emittance_t], + [ + 6.4214719960819659e-005, + 3.6603372435649773e-005, + 1.9955175623579313e-004, + 1.0198263116327677e-010, + 1.0308359092878036e-010, + 4.0035161705244885e-010, + ], + rtol=rtol, + atol=atol, +) + + +print("") +print("Final Beam:") +sigx, sigy, sigt, emittance_x, emittance_y, emittance_t = get_moments(final) +print(f" sigx={sigx:e} sigy={sigy:e} sigt={sigt:e}") +print( + f" emittance_x={emittance_x:e} emittance_y={emittance_y:e} emittance_t={emittance_t:e}" +) + +atol = 0.0 # ignored +rtol = 2.2e12 * num_particles**-0.5 # from random sampling of a smooth distribution +print(f" rtol={rtol} (ignored: atol~={atol})") + +assert np.allclose( + [sigx, sigy, sigt, emittance_x, emittance_y, emittance_t], + [ + 1.922660e-03, + 2.166654e-05, + 1.101353e-04, + 8.561046e-09, + 1.020439e-10, + 8.569865e-09, + ], + rtol=rtol, + atol=atol, +) + +print("") +print("Initial eigenemittances:") +emittance_1i, emittance_2i, emittance_3i = get_eigenemittances(initial_beam) +print(f" emittance_1={emittance_1i:e} emittance_2={emittance_2i:e} emittance_3={emittance_3i:e}") + +print("") +print("Final eigenemittances:") +emittance_1f, emittance_2f, emittance_3f = get_eigenemittances(final_beam) +print(f" emittance_1={emittance_1f:e} emittance_2={emittance_2f:e} emittance_3={emittance_3f:e}") + +atol = 0.0 # ignored +rtol = 3.5 * num_particles**-0.5 # from random sampling of a smooth distribution +print(f" rtol={rtol} (ignored: atol~={atol})") + +assert np.allclose( + [emittance_1f, emittance_2f, emittance_3f], + [ + emittance_1i, + emittance_2i, + emittance_3i, + ], + rtol=rtol, + atol=atol, +) diff --git a/examples/coupled_optics/input_coupled_optics.in b/examples/coupled_optics/input_coupled_optics.in new file mode 100644 index 000000000..c18a93449 --- /dev/null +++ b/examples/coupled_optics/input_coupled_optics.in @@ -0,0 +1,71 @@ +############################################################################### +# Particle Beam(s) +############################################################################### +beam.npart = 10000 +beam.units = static +beam.kin_energy = 5.0e3 +beam.charge = 1.0e-9 +beam.particle = electron +beam.distribution = waterbag +beam.lambdaX = 2.2951017632e-5 +beam.lambdaY = 1.3084093142e-5 +beam.lambdaT = 5.5555553e-8 +beam.lambdaPx = 1.598353425e-6 +beam.lambdaPy = 2.803697378e-6 +beam.lambdaPt = 2.000000000e-6 +beam.muxpx = 0.933345606203060 +beam.muypy = 0.933345606203060 +beam.mutpt = 0.999999961419755 + + +############################################################################### +# Beamline: lattice elements and segments +############################################################################### +lattice.elements = monitor sbend1 dipedge1 sol drift1 dipedge2 sbend2 drift2 monitor +lattice.nslice = 25 + +sbend1.type = sbend +sbend1.ds = 0.500194828041958 # projected length 0.5 m, angle 2.77 deg +sbend1.rc = -10.3462283686195526 + +drift1.type = drift +drift1.ds = 5.0058489435 # projected length 5 m + +sbend2.type = sbend +sbend2.ds = 0.500194828041958 # projected length 0.5 m, angle 2.77 deg +sbend2.rc = 10.3462283686195526 + +drift2.type = drift +drift2.ds = 0.5 + +dipedge1.type = dipedge # dipole edge focusing +dipedge1.psi = -0.048345620280243 +dipedge1.rc = -10.3462283686195526 +dipedge1.g = 0.0 +dipedge1.K2 = 0.0 + +dipedge2.type = dipedge +dipedge2.psi = 0.048345620280243 +dipedge2.rc = 10.3462283686195526 +dipedge2.g = 0.0 +dipedge2.K2 = 0.0 + +sol.type = solenoid +sol.ds = 3.820395 +sol.ks = 0.8223219329893234 + +monitor.type = beam_monitor +monitor.backend = h5 + + +############################################################################### +# Algorithms +############################################################################### +algo.particle_shape = 2 +algo.space_charge = false + + +############################################################################### +# Diagnostics +############################################################################### +diag.slice_step_diagnostics = true diff --git a/examples/coupled_optics/run_coupled_optics.py b/examples/coupled_optics/run_coupled_optics.py new file mode 100644 index 000000000..21e6c1af1 --- /dev/null +++ b/examples/coupled_optics/run_coupled_optics.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +# +# Copyright 2022-2023 ImpactX contributors +# Authors: Marco Garten, Axel Huebl, Chad Mitchell +# License: BSD-3-Clause-LBNL +# +# -*- coding: utf-8 -*- + +from impactx import ImpactX, distribution, elements + +sim = ImpactX() + +# set numerical parameters and IO control +sim.particle_shape = 2 # B-spline order +sim.space_charge = False +# sim.diagnostics = False # benchmarking +sim.slice_step_diagnostics = True + +# domain decomposition & space charge mesh +sim.init_grids() + +# load a 5 GeV electron beam with an initial +# normalized transverse rms emittance of 1 um +kin_energy_MeV = 5.0e3 # reference energy +bunch_charge_C = 1.0e-9 # used with space charge +npart = 10000 # number of macro particles + +# reference particle +ref = sim.particle_container().ref_particle() +ref.set_charge_qe(-1.0).set_mass_MeV(0.510998950).set_kin_energy_MeV(kin_energy_MeV) + +# particle bunch +distr = distribution.Waterbag( + lambdaX=2.2951017632e-5, + lambdaY=1.3084093142e-5, + lambdaT=5.5555553e-8, + lambdaPx=1.598353425e-6, + lambdaPy=2.803697378e-6, + lambdaPt=2.000000000e-6, + muxpx=0.933345606203060, + muypy=0.933345606203060, + mutpt=0.999999961419755, +) +sim.add_particles(bunch_charge_C, distr, npart) + +# add beam diagnostics +monitor = elements.BeamMonitor("monitor", backend="h5") + +# design the accelerator lattice +ns = 25 # number of slices per ds in the element +rc = 10.3462283686195526 # bend radius (meters) +psi = 0.048345620280243 # pole face rotation angle (radians) +lb = 0.500194828041958 # bend arc length (meters) + +# Drift elements +dr1 = elements.Drift(ds=5.0058489435, nslice=ns) +dr2 = elements.Drift(ds=0.5, nslice=ns) + +# Bend elements +sbend1 = elements.Sbend(ds=lb, rc=-rc, nslice=ns) +sbend2 = elements.Sbend(ds=lb, rc=rc, nslice=ns) + +# Dipole Edge Focusing elements +dipedge1 = elements.DipEdge(psi=-psi, rc=-rc, g=0.0, K2=0.0) +dipedge2 = elements.DipEdge(psi=psi, rc=rc, g=0.0, K2=0.0) + +# Solenoid element +sol = elements.Sol(ds=3.820395, ks=0.8223219329893234) + +lattice_coupled = [sbend1, dipedge1, sol, dr1, dipedge2, sbend2, dr2] + +sim.lattice.append(monitor) +sim.lattice.extend(lattice_coupled) +sim.lattice.append(monitor) + +# run simulation +sim.evolve() + +# clean shutdown +sim.finalize() From beccb40dc001c034d3fb686cec9fafb6c09e4137 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 14 Sep 2024 01:24:35 +0000 Subject: [PATCH 15/54] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- examples/coupled_optics/analysis_coupled_optics.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/coupled_optics/analysis_coupled_optics.py b/examples/coupled_optics/analysis_coupled_optics.py index ca6e5c7a8..04b3eb998 100755 --- a/examples/coupled_optics/analysis_coupled_optics.py +++ b/examples/coupled_optics/analysis_coupled_optics.py @@ -115,12 +115,16 @@ def get_eigenemittances(openpmd_beam): print("") print("Initial eigenemittances:") emittance_1i, emittance_2i, emittance_3i = get_eigenemittances(initial_beam) -print(f" emittance_1={emittance_1i:e} emittance_2={emittance_2i:e} emittance_3={emittance_3i:e}") +print( + f" emittance_1={emittance_1i:e} emittance_2={emittance_2i:e} emittance_3={emittance_3i:e}" +) print("") print("Final eigenemittances:") emittance_1f, emittance_2f, emittance_3f = get_eigenemittances(final_beam) -print(f" emittance_1={emittance_1f:e} emittance_2={emittance_2f:e} emittance_3={emittance_3f:e}") +print( + f" emittance_1={emittance_1f:e} emittance_2={emittance_2f:e} emittance_3={emittance_3f:e}" +) atol = 0.0 # ignored rtol = 3.5 * num_particles**-0.5 # from random sampling of a smooth distribution From d12e44c46662ba40822a167b9024f80786811435 Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Fri, 13 Sep 2024 18:36:47 -0700 Subject: [PATCH 16/54] Add documentation. --- docs/source/dataanalysis/dataanalysis.rst | 2 ++ docs/source/usage/examples.rst | 2 ++ examples/CMakeLists.txt | 17 +++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/docs/source/dataanalysis/dataanalysis.rst b/docs/source/dataanalysis/dataanalysis.rst index 4371f317c..6bc551c10 100644 --- a/docs/source/dataanalysis/dataanalysis.rst +++ b/docs/source/dataanalysis/dataanalysis.rst @@ -93,6 +93,8 @@ The code writes out the values in an ASCII file prefixed ``reduced_beam_characte Horizontal and vertical dispersion (unit: meter) * ``dispersion_px``, ``dispersion_py`` Derivative of horizontal and vertical dispersion (unit: dimensionless) +* ``emittance_1``, ``emittance_2``, ``emittance_3`` + Normalized rms beam eigenemittances (aka mode emittances) (unit: meter) * ``charge`` Total beam charge (unit: Coulomb) diff --git a/docs/source/usage/examples.rst b/docs/source/usage/examples.rst index 426881b7f..3eed51f4d 100644 --- a/docs/source/usage/examples.rst +++ b/docs/source/usage/examples.rst @@ -33,6 +33,8 @@ Single Particle Dynamics examples/achromatic_spectrometer/README.rst examples/fodo_programmable/README.rst examples/dogleg/README.rst + examples/coupled_optics/README.rst + Collective Effects ------------------ diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index d33221240..5953402bd 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -959,3 +959,20 @@ add_impactx_test(dogleg.py examples/dogleg/analysis_dogleg.py OFF # no plot script yet ) + +# Coupled Optics ############################################################# +# +# w/o space charge +add_impactx_test(coupled-optics + examples/dogleg/input_coupled_optics.in + ON # ImpactX MPI-parallel + examples/dogleg/analysis_coupled_optics.py + OFF # no plot script yet +) +add_impactx_test(coupled-optics.py + examples/dogleg/run_coupled_optics.py + OFF # ImpactX MPI-parallel + examples/dogleg/analysis_coupled_optics.py + OFF # no plot script yet +) + From b3fe78a3e5bf025768c903bba7dcd2d9b4264386 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 14 Sep 2024 01:37:18 +0000 Subject: [PATCH 17/54] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- examples/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 5953402bd..ee5293572 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -975,4 +975,3 @@ add_impactx_test(coupled-optics.py examples/dogleg/analysis_coupled_optics.py OFF # no plot script yet ) - From 7bd8c5a1741fb4fc6d106a31e9f565a2cdebea76 Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Fri, 13 Sep 2024 19:26:29 -0700 Subject: [PATCH 18/54] Update CMakeLists.txt Corrected path to benchmark test files. --- examples/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ee5293572..f43eff4d6 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -964,13 +964,13 @@ add_impactx_test(dogleg.py # # w/o space charge add_impactx_test(coupled-optics - examples/dogleg/input_coupled_optics.in + examples/coupled_optics/input_coupled_optics.in ON # ImpactX MPI-parallel examples/dogleg/analysis_coupled_optics.py OFF # no plot script yet ) add_impactx_test(coupled-optics.py - examples/dogleg/run_coupled_optics.py + examples/coupled_optics/run_coupled_optics.py OFF # ImpactX MPI-parallel examples/dogleg/analysis_coupled_optics.py OFF # no plot script yet From 8d001eb135cc7c39dc736c92989a1ecdffe01d99 Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Fri, 13 Sep 2024 19:40:42 -0700 Subject: [PATCH 19/54] Update CMakeLists.txt Update path for analysis scripts. --- examples/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f43eff4d6..ce9f905f4 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -966,12 +966,12 @@ add_impactx_test(dogleg.py add_impactx_test(coupled-optics examples/coupled_optics/input_coupled_optics.in ON # ImpactX MPI-parallel - examples/dogleg/analysis_coupled_optics.py + examples/coupled_optics/analysis_coupled_optics.py OFF # no plot script yet ) add_impactx_test(coupled-optics.py examples/coupled_optics/run_coupled_optics.py OFF # ImpactX MPI-parallel - examples/dogleg/analysis_coupled_optics.py + examples/coupled_optics/analysis_coupled_optics.py OFF # no plot script yet ) From 27e98820feec0bece4188dab7cd1aa9ab27e0b78 Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Fri, 13 Sep 2024 20:11:06 -0700 Subject: [PATCH 20/54] Normalize momenta by mc (dynamical units) for eigenemittances. --- .../ReducedBeamCharacteristics.cpp | 98 +++++++------------ 1 file changed, 35 insertions(+), 63 deletions(-) diff --git a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp index 71637c404..2970c1c0d 100644 --- a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp +++ b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp @@ -34,6 +34,9 @@ namespace impactx::diagnostics RefPart const ref_part = pc.GetRefParticle(); // reference particle charge in C amrex::ParticleReal const q_C = ref_part.charge; + // reference particle relativistic beta*gamma + amrex::ParticleReal const bg = ref_part.beta_gamma(); + amrex::ParticleReal const bg2 = bg*bg; // preparing access to particle data: SoA using PType = typename ImpactXParticleContainer::SuperParticleType; @@ -304,47 +307,49 @@ namespace impactx::diagnostics // Calculate eigenemittances (optional) amrex::Array2D Sigma; - amrex::ParticleReal emittance_1 = emittance_x; - amrex::ParticleReal emittance_2 = emittance_y; - amrex::ParticleReal emittance_3 = emittance_t; + amrex::ParticleReal emittance_1 = emittance_x * bg; + amrex::ParticleReal emittance_2 = emittance_y * bg; + amrex::ParticleReal emittance_3 = emittance_t * bg; bool compute_eigenemittances = true; if (compute_eigenemittances) { + // Store the covariance matrix in dynamical variables: Sigma(1,1) = x_ms; - Sigma(1,2) = xpx; + Sigma(1,2) = xpx * bg; Sigma(1,3) = xy; - Sigma(1,4) = xpy; + Sigma(1,4) = xpy * bg; Sigma(1,5) = xt; - Sigma(1,6) = xpt; - Sigma(2,1) = xpx; - Sigma(2,2) = px_ms; - Sigma(2,3) = pxy; - Sigma(2,4) = pxpy; - Sigma(2,5) = pxt; - Sigma(2,6) = pxpt; + Sigma(1,6) = xpt * bg; + Sigma(2,1) = xpx * bg; + Sigma(2,2) = px_ms * bg2; + Sigma(2,3) = pxy * bg; + Sigma(2,4) = pxpy * bg2; + Sigma(2,5) = pxt * bg; + Sigma(2,6) = pxpt * bg2; Sigma(3,1) = xy; - Sigma(3,2) = pxy; + Sigma(3,2) = pxy * bg; Sigma(3,3) = y_ms; - Sigma(3,4) = ypy; + Sigma(3,4) = ypy * bg; Sigma(3,5) = yt; - Sigma(3,6) = ypt; - Sigma(4,1) = xpy; - Sigma(4,2) = pxpy; - Sigma(4,3) = ypy; - Sigma(4,4) = py_ms; - Sigma(4,5) = pyt; - Sigma(4,6) = pypt; + Sigma(3,6) = ypt * bg; + Sigma(4,1) = xpy * bg; + Sigma(4,2) = pxpy * bg2; + Sigma(4,3) = ypy * bg; + Sigma(4,4) = py_ms * bg2; + Sigma(4,5) = pyt * bg; + Sigma(4,6) = pypt * bg2; Sigma(5,1) = xt; - Sigma(5,2) = pxt; + Sigma(5,2) = pxt * bg; Sigma(5,3) = yt; - Sigma(5,4) = pyt; + Sigma(5,4) = pyt * bg; Sigma(5,5) = t_ms; - Sigma(5,6) = tpt; - Sigma(6,1) = xpt; - Sigma(6,2) = pxpt; - Sigma(6,3) = ypt; - Sigma(6,4) = pypt; - Sigma(6,5) = tpt; - Sigma(6,6) = pt_ms; + Sigma(5,6) = tpt * bg; + Sigma(6,1) = xpt * bg; + Sigma(6,2) = pxpt * bg2; + Sigma(6,3) = ypt * bg; + Sigma(6,4) = pypt * bg2; + Sigma(6,5) = tpt * bg; + Sigma(6,6) = pt_ms * bg2; + // Calculate eigenemittances std::tuple emittances = Eigenemittances(Sigma); emittance_1 = std::get<0>(emittances); emittance_2 = std::get<1>(emittances); @@ -394,39 +399,6 @@ namespace impactx::diagnostics data["emittance_2"] = emittance_2; data["emittance_3"] = emittance_3; - // The following lines are added temporarily, for the sole - // purpose of benchmarking the eigenemittance output for - // a given beam covariance matrix Sigma. - //amrex::Array2D Sigma; - for (int i = 1; i < 7; i++) { - for (int j = 1; j < 7; j++) { - Sigma(i,j) = 0.0; - } - } - for (int i = 1; i<7; i++) { - Sigma(i,i) = 1.0; - } - Sigma(1,1) = 3.0; - Sigma(1,2) = 2.0; - Sigma(2,1) = 2.0; - Sigma(2,2) = 3.0; - - Sigma(3,3) = 1.0; - Sigma(3,4) = 0.5; - Sigma(4,3) = 0.5; - Sigma(4,4) = 1.0; - - Sigma(5,5) = 4.0; - Sigma(5,6) = 1.0; - Sigma(6,5) = 1.0; - Sigma(6,6) = 4.0; - - Sigma(1,6) = 1.0; - Sigma(6,1) = 1.0; - - //std::tuple emittances = Eigenemittances(Sigma); - //std::cout << "Emittances = " << std::get<0>(emittances) << " " << std::get<1>(emittances) << " " << std::get<2>(emittances); - return data; } } // namespace impactx::diagnostics From f33bd598a396d5718835b034357d0e8f0bfee785 Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Mon, 16 Sep 2024 11:25:58 -0700 Subject: [PATCH 21/54] Add alternative routine for cubic roots. --- .../diagnostics/CovarianceMatrixMath.H | 76 ++++++++++++++++++- .../diagnostics/EmittanceInvariants.cpp | 8 +- 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/particles/diagnostics/CovarianceMatrixMath.H b/src/particles/diagnostics/CovarianceMatrixMath.H index 7e91d1274..15efacfb0 100644 --- a/src/particles/diagnostics/CovarianceMatrixMath.H +++ b/src/particles/diagnostics/CovarianceMatrixMath.H @@ -13,7 +13,9 @@ #include #include #include +#include #include +#include namespace impactx::diagnostics { @@ -33,7 +35,7 @@ namespace impactx::diagnostics amrex::ParticleReal, amrex::ParticleReal, amrex::ParticleReal> - CubicRoots ( + CubicRootsTrig ( amrex::ParticleReal a, amrex::ParticleReal b, amrex::ParticleReal c, @@ -82,6 +84,78 @@ namespace impactx::diagnostics } + /** Function to return the roots of a cubic polynomial ax^3 + bx^2 + cx + d. + * The algebraic form of Cardano's formula is used. + * This implementation expects three real roots, which is verified + * by checking the sign of the discriminant. + * + * @param[in] a coefficient of cubic term + * @param[in] b coefficient of quadratic term + * @param[in] c coefficient of linear term + * @param[in] d coefficient of constant term + * @returns tuple of three real roots + */ + std::tuple< + amrex::ParticleReal, + amrex::ParticleReal, + amrex::ParticleReal> + CubicRootsAlg ( + amrex::ParticleReal a, + amrex::ParticleReal b, + amrex::ParticleReal c, + amrex::ParticleReal d + ) + { + using namespace amrex::literals; + using Complex = amrex::GpuComplex; + + std::tuple roots; + amrex::ParticleReal x1 = 0.0_prt; + amrex::ParticleReal x2 = 0.0_prt; + amrex::ParticleReal x3 = 0.0_prt; + + amrex::ParticleReal Q = (3.0_prt*a*c - pow(b,2))/(9.0_prt * pow(a,2)); + amrex::ParticleReal R = (9.0_prt*a*b*c - 27_prt*pow(a,2)*d - 2.0_prt*pow(b,3))/(54.0_prt*pow(a,3)); + amrex::ParticleReal discriminant = pow(Q,3) + pow(R,2); + + // Define complex variable C + Complex Qc(Q,0.0_prt); + Complex Rc(R,0.0_prt); + Complex Dc(discriminant,0.0_prt); + Complex C = pow(-Rc + sqrt(Dc),1.0/3.0); + + // Define a cubic root of unity xi + amrex::ParticleReal xire = -1.0/2.0; + amrex::ParticleReal xiim = sqrt(3.0)/2.0; + Complex xi(xire,xiim); + + //Three roots in algebraic form. + + if (C.m_real == 0.0_prt && C.m_imag == 0.0_prt){ // Special case of a triple root + + x1 = - b/(3.0_prt*a); + x2 = - b/(3.0_prt*a); + x3 = - b/(3.0_prt*a); + + } else { + + Complex z1 = Q/C - C - b/(3.0*a); + Complex z2 = Q/(xi*C) - xi*C - b/(3.0*a); + Complex z3 = Q/(pow(xi,2)*C) - pow(xi,2)*C - b/(3.0*a); + x1 = z2.m_real; + x2 = z1.m_real; + x3 = z3.m_real; + } + + //std::cout << "Discriminant, Q, R " << discriminant << " " << Q << " " << R << "\n"; + //std::cout << "Re(C), Im(C) " << C.m_real << " " << C.m_imag << "\n"; + //std::cout << "Return x1, x2, x3 " << x1 << " " << x2 << " " << x3 << "\n"; + + roots = std::make_tuple(x1,x2,x3); + return roots; + } + + /** Function to take the trace of a square 6x6 matrix. * * @param[in] A a square matrix diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index ed9dfddc0..f4e26b42a 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -122,14 +122,14 @@ namespace impactx::diagnostics //std::cout << "Return a,b,c,d " << a << " " << b << " " << c << " " << d << "\n"; // Solve for the roots to obtain the eigenemittances. - roots = CubicRoots(a,b,c,d); + // Caution: The order of e1,e2,e3 should be consistent with the + // order ex,ey,et in the limit of uncoupled transport. + // The order below is important and has been checked. + roots = CubicRootsAlg(a,b,c,d); amrex::ParticleReal e1 = sqrt(std::get<1>(roots)); amrex::ParticleReal e2 = sqrt(std::get<2>(roots)); amrex::ParticleReal e3 = sqrt(std::get<0>(roots)); - // Caution: The order of e1,e2,e3 should be consistent with the - // order ex,ey,et in the limit of uncoupled transport. The - // ordering remains to be carefully checked (TODO). emittances = std::make_tuple(e1,e2,e3); return emittances; } From f22eaaede7bda93e877b40b20d9fed56c18b8bc5 Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:40:05 -0700 Subject: [PATCH 22/54] Update EmittanceInvariants.cpp Update default cubic roots alg. --- src/particles/diagnostics/EmittanceInvariants.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index f4e26b42a..54a8a837d 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -125,7 +125,7 @@ namespace impactx::diagnostics // Caution: The order of e1,e2,e3 should be consistent with the // order ex,ey,et in the limit of uncoupled transport. // The order below is important and has been checked. - roots = CubicRootsAlg(a,b,c,d); + roots = CubicRootsTrig(a,b,c,d); amrex::ParticleReal e1 = sqrt(std::get<1>(roots)); amrex::ParticleReal e2 = sqrt(std::get<2>(roots)); amrex::ParticleReal e3 = sqrt(std::get<0>(roots)); From e4a942145ebd72a03a80c9339e8df703a05ad7e1 Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:45:44 -0700 Subject: [PATCH 23/54] Update CovarianceMatrixMath.H Avoid subtracting complex and double types. --- src/particles/diagnostics/CovarianceMatrixMath.H | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/particles/diagnostics/CovarianceMatrixMath.H b/src/particles/diagnostics/CovarianceMatrixMath.H index 15efacfb0..59c3c4f5f 100644 --- a/src/particles/diagnostics/CovarianceMatrixMath.H +++ b/src/particles/diagnostics/CovarianceMatrixMath.H @@ -139,12 +139,12 @@ namespace impactx::diagnostics } else { - Complex z1 = Q/C - C - b/(3.0*a); - Complex z2 = Q/(xi*C) - xi*C - b/(3.0*a); - Complex z3 = Q/(pow(xi,2)*C) - pow(xi,2)*C - b/(3.0*a); - x1 = z2.m_real; - x2 = z1.m_real; - x3 = z3.m_real; + Complex z1 = Qc/C - C; + Complex z2 = Qc/(xi*C) - xi*C; + Complex z3 = Qc/(pow(xi,2)*C) - pow(xi,2)*C; + x1 = z2.m_real - b/(3.0*a); + x2 = z1.m_real - b/(3.0*a); + x3 = z3.m_real - b/(3.0*a); } //std::cout << "Discriminant, Q, R " << discriminant << " " << Q << " " << R << "\n"; From 1a62b70710bc9c7c4639280ec9759e7b05a0971f Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Mon, 16 Sep 2024 12:20:52 -0700 Subject: [PATCH 24/54] Temporarily comment pytest test_transformation. --- tests/python/test_transformation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/test_transformation.py b/tests/python/test_transformation.py index 93b52966c..13bc05104 100644 --- a/tests/python/test_transformation.py +++ b/tests/python/test_transformation.py @@ -81,7 +81,7 @@ def test_transformation(): for key, val in rbc_s0.items(): if not np.isclose(val, rbc_s[key], rtol=rtol, atol=atol): print(f"initial[{key}]={val}, final[{key}]={rbc_s[key]} not equal") - assert np.isclose(val, rbc_s[key], rtol=rtol, atol=atol) +// assert np.isclose(val, rbc_s[key], rtol=rtol, atol=atol) # assert that the t-based beam is different, at least in the following keys: large_st_diff_keys = [ "beta_x", From 8fdee821c3f9264a2723f8438ef4d4a3534537c1 Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Mon, 16 Sep 2024 12:27:55 -0700 Subject: [PATCH 25/54] Update test_transformation.py Modify comment syntax c++ -> Python. --- tests/python/test_transformation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/test_transformation.py b/tests/python/test_transformation.py index 13bc05104..171816194 100644 --- a/tests/python/test_transformation.py +++ b/tests/python/test_transformation.py @@ -81,7 +81,7 @@ def test_transformation(): for key, val in rbc_s0.items(): if not np.isclose(val, rbc_s[key], rtol=rtol, atol=atol): print(f"initial[{key}]={val}, final[{key}]={rbc_s[key]} not equal") -// assert np.isclose(val, rbc_s[key], rtol=rtol, atol=atol) +# assert np.isclose(val, rbc_s[key], rtol=rtol, atol=atol) # assert that the t-based beam is different, at least in the following keys: large_st_diff_keys = [ "beta_x", From 90706542d214e83d24cc6d6378f636a419c8b57f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 19:29:19 +0000 Subject: [PATCH 26/54] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/python/test_transformation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/test_transformation.py b/tests/python/test_transformation.py index 171816194..1d7331ae0 100644 --- a/tests/python/test_transformation.py +++ b/tests/python/test_transformation.py @@ -81,7 +81,7 @@ def test_transformation(): for key, val in rbc_s0.items(): if not np.isclose(val, rbc_s[key], rtol=rtol, atol=atol): print(f"initial[{key}]={val}, final[{key}]={rbc_s[key]} not equal") -# assert np.isclose(val, rbc_s[key], rtol=rtol, atol=atol) + # assert np.isclose(val, rbc_s[key], rtol=rtol, atol=atol) # assert that the t-based beam is different, at least in the following keys: large_st_diff_keys = [ "beta_x", From 8cfafc6491887e4e9513ce9047355df77bb26e5a Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Mon, 16 Sep 2024 15:15:45 -0700 Subject: [PATCH 27/54] Delete commented debugging print statements. --- src/particles/diagnostics/CovarianceMatrixMath.H | 5 ----- src/particles/diagnostics/EmittanceInvariants.cpp | 1 - 2 files changed, 6 deletions(-) diff --git a/src/particles/diagnostics/CovarianceMatrixMath.H b/src/particles/diagnostics/CovarianceMatrixMath.H index 59c3c4f5f..76e646def 100644 --- a/src/particles/diagnostics/CovarianceMatrixMath.H +++ b/src/particles/diagnostics/CovarianceMatrixMath.H @@ -76,8 +76,6 @@ namespace impactx::diagnostics } - //std::cout << "Discriminant, Q, R " << discriminant << " " << Q << " " << R << "\n"; - //std::cout << "Return x1, x2, x3 " << x1 << " " << x2 << " " << x3 << "\n"; roots = std::make_tuple(x1,x2,x3); return roots; @@ -147,9 +145,6 @@ namespace impactx::diagnostics x3 = z3.m_real - b/(3.0*a); } - //std::cout << "Discriminant, Q, R " << discriminant << " " << Q << " " << R << "\n"; - //std::cout << "Re(C), Im(C) " << C.m_real << " " << C.m_imag << "\n"; - //std::cout << "Return x1, x2, x3 " << x1 << " " << x2 << " " << x3 << "\n"; roots = std::make_tuple(x1,x2,x3); return roots; diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index 54a8a837d..b5b2318b4 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -75,7 +75,6 @@ namespace impactx::diagnostics I4 = +impactx::diagnostics::TraceMat(S4)/2.0_prt; I6 = -impactx::diagnostics::TraceMat(S6)/2.0_prt; - //std::cout << "Return I2, I4, I6 " << I2 << " " << I4 << " " << I6 << "\n"; invariants = std::make_tuple(I2,I4,I6); return invariants; From ea114ffa0569f1f0af81e011a7205cb9fe23ebca Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Mon, 16 Sep 2024 16:22:45 -0700 Subject: [PATCH 28/54] Update EmittanceInvariants.H Add literature citations. --- .../diagnostics/EmittanceInvariants.H | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/particles/diagnostics/EmittanceInvariants.H b/src/particles/diagnostics/EmittanceInvariants.H index 90fb21618..44b6b8e77 100644 --- a/src/particles/diagnostics/EmittanceInvariants.H +++ b/src/particles/diagnostics/EmittanceInvariants.H @@ -21,11 +21,18 @@ namespace impactx::diagnostics { - /** Returns the three independent kinetic invariants + /** Returns the three independent kinematic moment invariants * denoted I2, I4, and I6 as constructed from the 6x6 * beam covariance matrix. These three quantities are invariant * under any linear symplectic transport map, and are used in the - * calculation of the three eigenemittances. + * calculation of the three eigenemittances, as described in: + * + * G. Rangarajan, F. Neri, and A. Dragt, "Generalized Emittance + * Invariants," in Proc. 1989 IEEE Part. Accel. Conf., Chicago, IL, + * 1989, doi:10.1109/PAC.1989.73422. + * A. Dragt, F. Neri, and G. Rangarajan, "General Moment Invariants + * for Linear Hamiltonian Systems," Phys. Rev. A 45, 2572-2585 (1992), + * doi:10.1103/PhysRevA.45.2572. * * @param[in] Sigma symmetric 6x6 covariance matrix * @returns tuple containing invariants I2, I4, and I6 @@ -43,7 +50,14 @@ namespace impactx::diagnostics * beam covariance matrix. These three quantities are invariant * under any linear symplectic transport map, and reduce to * the projected normalized rms emittances in the limit of - * uncoupled transport. + * uncoupled transport. These quantities are described in: + * + * G. Rangarajan, F. Neri, and A. Dragt, "Generalized Emittance + * Invariants," in Proc. 1989 IEEE Part. Accel. Conf., Chicago, IL, + * 1989, doi:10.1109/PAC.1989.73422. + * A. Dragt, F. Neri, and G. Rangarajan, "General Moment Invariants + * for Linear Hamiltonian Systems," Phys. Rev. A 45, 2572-2585 (1992), + * doi:10.1103/PhysRevA.45.2572. * * @param[in] Sigma symmetric 6x6 covariance matrix * @returns tuple containing eigenemittances e1, e2, and e3 From 101803c8ab94ee5b420c57f2e1f38ee181ab09ff Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Mon, 16 Sep 2024 16:28:58 -0700 Subject: [PATCH 29/54] Update EmittanceInvariants.cpp Add literature citations. --- src/particles/diagnostics/EmittanceInvariants.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index b5b2318b4..eb0110916 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -111,7 +111,11 @@ namespace impactx::diagnostics amrex::ParticleReal I4 = std::get<1>(invariants); amrex::ParticleReal I6 = std::get<2>(invariants); - // Construct the coefficients of the cubic polynomial + // Construct the coefficients of the cubic polynomial. + // This expression for the characteristic polynomial can be found in: + // V. Balandin, W. Decking, and N. Golubeva, "Relations Between Projected + // Emittances and Eigenemittances," in IPAC2018, Shanghai, China, 2013, + // doi:10.48550/arXiv.1305.1532. amrex::ParticleReal a = 1.0_prt; amrex::ParticleReal b = -I2; amrex::ParticleReal c = (pow(I2,2)-I4)/2.0_prt; From 2ee73f4c806a7b6fad0087f725615af4b33f5a6c Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Wed, 18 Sep 2024 18:08:54 -0700 Subject: [PATCH 30/54] Apply suggestions from code review Correct typo; avoid possible NaN resulting from sqrt. --- src/particles/diagnostics/EmittanceInvariants.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index eb0110916..ad82d9555 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -114,7 +114,7 @@ namespace impactx::diagnostics // Construct the coefficients of the cubic polynomial. // This expression for the characteristic polynomial can be found in: // V. Balandin, W. Decking, and N. Golubeva, "Relations Between Projected - // Emittances and Eigenemittances," in IPAC2018, Shanghai, China, 2013, + // Emittances and Eigenemittances," in IPAC2013, Shanghai, China, 2013, // doi:10.48550/arXiv.1305.1532. amrex::ParticleReal a = 1.0_prt; amrex::ParticleReal b = -I2; @@ -129,9 +129,9 @@ namespace impactx::diagnostics // order ex,ey,et in the limit of uncoupled transport. // The order below is important and has been checked. roots = CubicRootsTrig(a,b,c,d); - amrex::ParticleReal e1 = sqrt(std::get<1>(roots)); - amrex::ParticleReal e2 = sqrt(std::get<2>(roots)); - amrex::ParticleReal e3 = sqrt(std::get<0>(roots)); + amrex::ParticleReal e1 = sqrt(abs(std::get<1>(roots))); + amrex::ParticleReal e2 = sqrt(abs(std::get<2>(roots))); + amrex::ParticleReal e3 = sqrt(abs(std::get<0>(roots))); emittances = std::make_tuple(e1,e2,e3); return emittances; From 96818f27018554cf76473ec4bb28d176ef45f29f Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Wed, 18 Sep 2024 19:44:58 -0700 Subject: [PATCH 31/54] Update src/particles/diagnostics/EmittanceInvariants.cpp Use amrex::abs --- src/particles/diagnostics/EmittanceInvariants.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index ad82d9555..83a34b1cd 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -129,9 +129,9 @@ namespace impactx::diagnostics // order ex,ey,et in the limit of uncoupled transport. // The order below is important and has been checked. roots = CubicRootsTrig(a,b,c,d); - amrex::ParticleReal e1 = sqrt(abs(std::get<1>(roots))); - amrex::ParticleReal e2 = sqrt(abs(std::get<2>(roots))); - amrex::ParticleReal e3 = sqrt(abs(std::get<0>(roots))); + amrex::ParticleReal e1 = sqrt(amrex::abs(std::get<1>(roots))); + amrex::ParticleReal e2 = sqrt(amrex::abs(std::get<2>(roots))); + amrex::ParticleReal e3 = sqrt(amrex::abs(std::get<0>(roots))); emittances = std::make_tuple(e1,e2,e3); return emittances; From e6bd89840e38f532f89cdb82ec49ab4d63ffc5e9 Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Wed, 18 Sep 2024 19:55:55 -0700 Subject: [PATCH 32/54] Update EmittanceInvariants.cpp Revert to std --- src/particles/diagnostics/EmittanceInvariants.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index 83a34b1cd..a0fbc9d01 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -129,9 +129,9 @@ namespace impactx::diagnostics // order ex,ey,et in the limit of uncoupled transport. // The order below is important and has been checked. roots = CubicRootsTrig(a,b,c,d); - amrex::ParticleReal e1 = sqrt(amrex::abs(std::get<1>(roots))); - amrex::ParticleReal e2 = sqrt(amrex::abs(std::get<2>(roots))); - amrex::ParticleReal e3 = sqrt(amrex::abs(std::get<0>(roots))); + amrex::ParticleReal e1 = sqrt(std::abs(std::get<1>(roots))); + amrex::ParticleReal e2 = sqrt(std::abs(std::get<2>(roots))); + amrex::ParticleReal e3 = sqrt(std::abs(std::get<0>(roots))); emittances = std::make_tuple(e1,e2,e3); return emittances; From 06b63c286f4032b692c9eeb2638f2bd38e0ee94d Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Tue, 24 Sep 2024 13:42:41 -0700 Subject: [PATCH 33/54] Add emittance_1,2,3 print. --- src/particles/diagnostics/DiagnosticOutput.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/particles/diagnostics/DiagnosticOutput.cpp b/src/particles/diagnostics/DiagnosticOutput.cpp index fee8af6eb..433f7840f 100644 --- a/src/particles/diagnostics/DiagnosticOutput.cpp +++ b/src/particles/diagnostics/DiagnosticOutput.cpp @@ -57,6 +57,7 @@ namespace impactx::diagnostics << "beta_x" << " " << "beta_y" << " " << "beta_t" << " " << "dispersion_x" << " " << "dispersion_px" << " " << "dispersion_y" << " " << "dispersion_py" << " " + << "emittance_1" << " " << "emittance_2" << " " << "emittance_3" << " " << "charge_C" << " " << "\n"; } From 0e8ecf199ec47b2f01a0942781f7481430bcf3ba Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Tue, 24 Sep 2024 13:47:07 -0700 Subject: [PATCH 34/54] Finalize print of emittance_1,2,3. --- src/particles/diagnostics/DiagnosticOutput.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/particles/diagnostics/DiagnosticOutput.cpp b/src/particles/diagnostics/DiagnosticOutput.cpp index 433f7840f..170b09a3f 100644 --- a/src/particles/diagnostics/DiagnosticOutput.cpp +++ b/src/particles/diagnostics/DiagnosticOutput.cpp @@ -107,6 +107,7 @@ namespace impactx::diagnostics << rbc.at("beta_x") << " " << rbc.at("beta_y") << " " << rbc.at("beta_t") << " " << rbc.at("dispersion_x") << " " << rbc.at("dispersion_px") << " " << rbc.at("dispersion_y") << " " << rbc.at("dispersion_py") << " " + << rbc.at("emittance_1") << " " << rbc.at("emittance_2") << " " << rbc.at("emittance_3") << " " << rbc.at("charge_C") << "\n"; } // if( otype == OutputType::PrintReducedBeamCharacteristics) From 71bb1553ea227108e4e8e590bb8ddd0443bde2f0 Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Tue, 24 Sep 2024 14:20:53 -0700 Subject: [PATCH 35/54] Add ParmParse for optional calculation. --- examples/coupled_optics/input_coupled_optics.in | 1 + examples/coupled_optics/run_coupled_optics.py | 1 + .../diagnostics/ReducedBeamCharacteristics.cpp | 7 ++++++- src/python/ImpactX.cpp | 10 ++++++++++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/examples/coupled_optics/input_coupled_optics.in b/examples/coupled_optics/input_coupled_optics.in index c18a93449..f0ee840c4 100644 --- a/examples/coupled_optics/input_coupled_optics.in +++ b/examples/coupled_optics/input_coupled_optics.in @@ -69,3 +69,4 @@ algo.space_charge = false # Diagnostics ############################################################################### diag.slice_step_diagnostics = true +diag.eigenemittances = true diff --git a/examples/coupled_optics/run_coupled_optics.py b/examples/coupled_optics/run_coupled_optics.py index 21e6c1af1..c6e6632d1 100644 --- a/examples/coupled_optics/run_coupled_optics.py +++ b/examples/coupled_optics/run_coupled_optics.py @@ -15,6 +15,7 @@ sim.space_charge = False # sim.diagnostics = False # benchmarking sim.slice_step_diagnostics = True +sim.eigenemittances = True # domain decomposition & space charge mesh sim.init_grids() diff --git a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp index 2970c1c0d..a4716461e 100644 --- a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp +++ b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp @@ -310,7 +310,12 @@ namespace impactx::diagnostics amrex::ParticleReal emittance_1 = emittance_x * bg; amrex::ParticleReal emittance_2 = emittance_y * bg; amrex::ParticleReal emittance_3 = emittance_t * bg; - bool compute_eigenemittances = true; + + // Parse the diagnostic parameters + amrex::ParmParse pp_diag("diag"); + bool compute_eigenemittances = false; + pp_diag.queryAdd("eigenemittances", compute_eigenemittances); + if (compute_eigenemittances) { // Store the covariance matrix in dynamical variables: Sigma(1,1) = x_ms; diff --git a/src/python/ImpactX.cpp b/src/python/ImpactX.cpp index 0326ca496..02e15a4d7 100644 --- a/src/python/ImpactX.cpp +++ b/src/python/ImpactX.cpp @@ -223,6 +223,16 @@ void init_ImpactX (py::module& m) }, "Number of longitudinal bins used for CSR calculations (default: 150)." ) + .def_property("eigenemittances", + [](ImpactX & /* ix */) { + return detail::get_or_throw("diag", "eigenemittances"); + }, + [](ImpactX & /* ix */, bool const enable) { + amrex::ParmParse pp_diag("diag"); + pp_diag.add("eigenemittances", enable); + }, + "Enable or disable eigenemittance diagnostic calculations (default: disabled)." + ) .def_property("space_charge", [](ImpactX & /* ix */) { return detail::get_or_throw("algo", "space_charge"); From 49d5677a4e608aa70356703b9d49b82e4d4e2fe6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 21:21:57 +0000 Subject: [PATCH 36/54] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/particles/diagnostics/ReducedBeamCharacteristics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp index a4716461e..7e1d6a203 100644 --- a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp +++ b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp @@ -311,7 +311,7 @@ namespace impactx::diagnostics amrex::ParticleReal emittance_2 = emittance_y * bg; amrex::ParticleReal emittance_3 = emittance_t * bg; - // Parse the diagnostic parameters + // Parse the diagnostic parameters amrex::ParmParse pp_diag("diag"); bool compute_eigenemittances = false; pp_diag.queryAdd("eigenemittances", compute_eigenemittances); From 368410805599abb66e1e072f634975b35281e704 Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Tue, 24 Sep 2024 15:35:30 -0700 Subject: [PATCH 37/54] Update test_transformation.py Re-enable test_transformation.py. --- tests/python/test_transformation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/test_transformation.py b/tests/python/test_transformation.py index 1d7331ae0..aa00b349c 100644 --- a/tests/python/test_transformation.py +++ b/tests/python/test_transformation.py @@ -81,7 +81,7 @@ def test_transformation(): for key, val in rbc_s0.items(): if not np.isclose(val, rbc_s[key], rtol=rtol, atol=atol): print(f"initial[{key}]={val}, final[{key}]={rbc_s[key]} not equal") - # assert np.isclose(val, rbc_s[key], rtol=rtol, atol=atol) + assert np.isclose(val, rbc_s[key], rtol=rtol, atol=atol) # assert that the t-based beam is different, at least in the following keys: large_st_diff_keys = [ "beta_x", From c883ee884b868c52a03e833b077a3bbd718de3b2 Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Wed, 25 Sep 2024 10:25:58 -0700 Subject: [PATCH 38/54] Apply suggestions from code review Co-authored-by: Axel Huebl --- examples/coupled_optics/README.rst | 4 ++-- src/particles/diagnostics/CovarianceMatrixMath.H | 5 ++++- src/particles/diagnostics/EmittanceInvariants.H | 3 ++- src/particles/diagnostics/EmittanceInvariants.cpp | 9 ++++++--- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/examples/coupled_optics/README.rst b/examples/coupled_optics/README.rst index de06da044..ff17b9e20 100644 --- a/examples/coupled_optics/README.rst +++ b/examples/coupled_optics/README.rst @@ -1,7 +1,7 @@ .. _examples-coupled-optics: -Coupled optics -================ +Coupled Optics +============== This is a lattice illustrating fully coupled 6D transport. It is obtained from the example "dogleg" by adding a solenoid after the first bending dipole. The solenoid is identical to that found in the example "solenoid". diff --git a/src/particles/diagnostics/CovarianceMatrixMath.H b/src/particles/diagnostics/CovarianceMatrixMath.H index 76e646def..26f8caa42 100644 --- a/src/particles/diagnostics/CovarianceMatrixMath.H +++ b/src/particles/diagnostics/CovarianceMatrixMath.H @@ -11,11 +11,14 @@ #define COVARIANCE_MATRIX_MATH_H #include + #include #include #include -#include + #include +#include + namespace impactx::diagnostics { diff --git a/src/particles/diagnostics/EmittanceInvariants.H b/src/particles/diagnostics/EmittanceInvariants.H index 44b6b8e77..2d35db001 100644 --- a/src/particles/diagnostics/EmittanceInvariants.H +++ b/src/particles/diagnostics/EmittanceInvariants.H @@ -12,10 +12,11 @@ #include "particles/ImpactXParticleContainer.H" +#include #include #include -#include + namespace impactx::diagnostics diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index a0fbc9d01..54e05a8d9 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -9,13 +9,14 @@ */ #include "CovarianceMatrixMath.H" -#include #include #include #include + #include -#include +#include #include +#include namespace impactx::diagnostics @@ -56,7 +57,7 @@ namespace impactx::diagnostics // a change of sign. for (int i = 1; i < 7; i++) { for (int j = 1; j < 7; j++) { - if (j % 2) { + if (j % 2 == 1) { S1(i,j) = -Sigma(i,j+1); // if j is odd } else { @@ -99,6 +100,8 @@ namespace impactx::diagnostics amrex::Array2D Sigma ) { + BL_PROFILE("impactx::diagnostics::Eigenemittances"); + using namespace amrex::literals; std::tuple invariants; From 0172e10fa16f25b7e895c0f5f1b954c703b217ed Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Wed, 25 Sep 2024 10:32:16 -0700 Subject: [PATCH 39/54] Update EmittanceInvariants.cpp Add PROFILE header. --- src/particles/diagnostics/EmittanceInvariants.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index 54e05a8d9..397323c54 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include From 587a09582ff7621ba4b68514b35de1e1e92e18c8 Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:24:40 -0700 Subject: [PATCH 40/54] Update CovarianceMatrixMath.H Use math functions from std:: (sqrt, pow, sin, cos, etc) -> (std::sqrt, std::pow, std::sin, std::cos, etc). --- .../diagnostics/CovarianceMatrixMath.H | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/particles/diagnostics/CovarianceMatrixMath.H b/src/particles/diagnostics/CovarianceMatrixMath.H index 26f8caa42..20d218066 100644 --- a/src/particles/diagnostics/CovarianceMatrixMath.H +++ b/src/particles/diagnostics/CovarianceMatrixMath.H @@ -53,9 +53,9 @@ namespace impactx::diagnostics amrex::ParticleReal x2 = 0.0_prt; amrex::ParticleReal x3 = 0.0_prt; - amrex::ParticleReal Q = (3.0_prt*a*c - pow(b,2))/(9.0_prt * pow(a,2)); - amrex::ParticleReal R = (9.0_prt*a*b*c - 27_prt*pow(a,2)*d - 2.0_prt*pow(b,3))/(54.0_prt*pow(a,3)); - amrex::ParticleReal discriminant = pow(Q,3) + pow(R,2); + amrex::ParticleReal Q = (3.0_prt*a*c - std::pow(b,2))/(9.0_prt * std::pow(a,2)); + amrex::ParticleReal R = (9.0_prt*a*b*c - 27_prt*std::pow(a,2)*d - 2.0_prt*std::pow(b,3))/(54.0_prt*std::pow(a,3)); + amrex::ParticleReal discriminant = std::pow(Q,3) + std::pow(R,2); // Discriminant should be < 0. Otherwise, keep theta at default and throw an error. amrex::ParticleReal tol = 1.0e-12; //allow for roundoff error @@ -73,9 +73,9 @@ namespace impactx::diagnostics //Three real roots in trigonometric form. amrex::ParticleReal theta = acos(R/sqrt(-pow(Q,3))); - x1 = 2.0_prt*sqrt(-Q)*cos(theta/3.0_prt) - b/(3.0_prt*a); - x2 = 2.0_prt*sqrt(-Q)*cos(theta/3.0_prt + 2.0_prt*pi/3.0_prt) - b/(3.0_prt*a); - x3 = 2.0_prt*sqrt(-Q)*cos(theta/3.0_prt + 4.0_prt*pi/3.0_prt) - b/(3.0_prt*a); + x1 = 2.0_prt*std::sqrt(-Q)*std::cos(theta/3.0_prt) - b/(3.0_prt*a); + x2 = 2.0_prt*std::sqrt(-Q)*std::cos(theta/3.0_prt + 2.0_prt*pi/3.0_prt) - b/(3.0_prt*a); + x3 = 2.0_prt*std::sqrt(-Q)*std::cos(theta/3.0_prt + 4.0_prt*pi/3.0_prt) - b/(3.0_prt*a); } @@ -115,19 +115,19 @@ namespace impactx::diagnostics amrex::ParticleReal x2 = 0.0_prt; amrex::ParticleReal x3 = 0.0_prt; - amrex::ParticleReal Q = (3.0_prt*a*c - pow(b,2))/(9.0_prt * pow(a,2)); - amrex::ParticleReal R = (9.0_prt*a*b*c - 27_prt*pow(a,2)*d - 2.0_prt*pow(b,3))/(54.0_prt*pow(a,3)); - amrex::ParticleReal discriminant = pow(Q,3) + pow(R,2); + amrex::ParticleReal Q = (3.0_prt*a*c - std::pow(b,2))/(9.0_prt * std::pow(a,2)); + amrex::ParticleReal R = (9.0_prt*a*b*c - 27_prt*std::pow(a,2)*d - 2.0_prt*std::pow(b,3))/(54.0_prt*std::pow(a,3)); + amrex::ParticleReal discriminant = std::pow(Q,3) + std::pow(R,2); // Define complex variable C Complex Qc(Q,0.0_prt); Complex Rc(R,0.0_prt); Complex Dc(discriminant,0.0_prt); - Complex C = pow(-Rc + sqrt(Dc),1.0/3.0); + Complex C = std::pow(-Rc + std::sqrt(Dc),1.0/3.0); // Define a cubic root of unity xi amrex::ParticleReal xire = -1.0/2.0; - amrex::ParticleReal xiim = sqrt(3.0)/2.0; + amrex::ParticleReal xiim = std::sqrt(3.0)/2.0; Complex xi(xire,xiim); //Three roots in algebraic form. @@ -142,7 +142,7 @@ namespace impactx::diagnostics Complex z1 = Qc/C - C; Complex z2 = Qc/(xi*C) - xi*C; - Complex z3 = Qc/(pow(xi,2)*C) - pow(xi,2)*C; + Complex z3 = Qc/(std::pow(xi,2)*C) - std::pow(xi,2)*C; x1 = z2.m_real - b/(3.0*a); x2 = z1.m_real - b/(3.0*a); x3 = z3.m_real - b/(3.0*a); From 851b46adaa715b239087a572168168a0ab971c3d Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:25:33 -0700 Subject: [PATCH 41/54] Update src/particles/diagnostics/CovarianceMatrixMath.H Co-authored-by: Axel Huebl --- src/particles/diagnostics/CovarianceMatrixMath.H | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/particles/diagnostics/CovarianceMatrixMath.H b/src/particles/diagnostics/CovarianceMatrixMath.H index 20d218066..b2befad72 100644 --- a/src/particles/diagnostics/CovarianceMatrixMath.H +++ b/src/particles/diagnostics/CovarianceMatrixMath.H @@ -72,7 +72,7 @@ namespace impactx::diagnostics } else { //Three real roots in trigonometric form. - amrex::ParticleReal theta = acos(R/sqrt(-pow(Q,3))); + amrex::ParticleReal theta = std::acos(R/::sqrt(-::pow(Q,3))); x1 = 2.0_prt*std::sqrt(-Q)*std::cos(theta/3.0_prt) - b/(3.0_prt*a); x2 = 2.0_prt*std::sqrt(-Q)*std::cos(theta/3.0_prt + 2.0_prt*pi/3.0_prt) - b/(3.0_prt*a); x3 = 2.0_prt*std::sqrt(-Q)*std::cos(theta/3.0_prt + 4.0_prt*pi/3.0_prt) - b/(3.0_prt*a); From 45f21b975891e2070afa22e2f741b7bdbecc4d5b Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:26:21 -0700 Subject: [PATCH 42/54] Update CovarianceMatrixMath.H --- src/particles/diagnostics/CovarianceMatrixMath.H | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/particles/diagnostics/CovarianceMatrixMath.H b/src/particles/diagnostics/CovarianceMatrixMath.H index b2befad72..705fa09cc 100644 --- a/src/particles/diagnostics/CovarianceMatrixMath.H +++ b/src/particles/diagnostics/CovarianceMatrixMath.H @@ -72,7 +72,7 @@ namespace impactx::diagnostics } else { //Three real roots in trigonometric form. - amrex::ParticleReal theta = std::acos(R/::sqrt(-::pow(Q,3))); + amrex::ParticleReal theta = std::acos(R/std::sqrt(-std::pow(Q,3))); x1 = 2.0_prt*std::sqrt(-Q)*std::cos(theta/3.0_prt) - b/(3.0_prt*a); x2 = 2.0_prt*std::sqrt(-Q)*std::cos(theta/3.0_prt + 2.0_prt*pi/3.0_prt) - b/(3.0_prt*a); x3 = 2.0_prt*std::sqrt(-Q)*std::cos(theta/3.0_prt + 4.0_prt*pi/3.0_prt) - b/(3.0_prt*a); From 59f5b4d000403f4a0347b5c0b54def672da95cac Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:35:27 -0700 Subject: [PATCH 43/54] Update CovarianceMatrixMath.H Remove std::math for complex functions. --- src/particles/diagnostics/CovarianceMatrixMath.H | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/particles/diagnostics/CovarianceMatrixMath.H b/src/particles/diagnostics/CovarianceMatrixMath.H index 705fa09cc..c5a358608 100644 --- a/src/particles/diagnostics/CovarianceMatrixMath.H +++ b/src/particles/diagnostics/CovarianceMatrixMath.H @@ -123,7 +123,7 @@ namespace impactx::diagnostics Complex Qc(Q,0.0_prt); Complex Rc(R,0.0_prt); Complex Dc(discriminant,0.0_prt); - Complex C = std::pow(-Rc + std::sqrt(Dc),1.0/3.0); + Complex C = pow(-Rc + sqrt(Dc),1.0/3.0); // Define a cubic root of unity xi amrex::ParticleReal xire = -1.0/2.0; @@ -142,7 +142,7 @@ namespace impactx::diagnostics Complex z1 = Qc/C - C; Complex z2 = Qc/(xi*C) - xi*C; - Complex z3 = Qc/(std::pow(xi,2)*C) - std::pow(xi,2)*C; + Complex z3 = Qc/(pow(xi,2)*C) - pow(xi,2)*C; x1 = z2.m_real - b/(3.0*a); x2 = z1.m_real - b/(3.0*a); x3 = z3.m_real - b/(3.0*a); From 53024fa9c249844dd3c17a08782c6904a363454f Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Wed, 25 Sep 2024 20:42:00 -0700 Subject: [PATCH 44/54] Use amrex:: math for complex functions. --- src/particles/diagnostics/CovarianceMatrixMath.H | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/particles/diagnostics/CovarianceMatrixMath.H b/src/particles/diagnostics/CovarianceMatrixMath.H index c5a358608..63aefd772 100644 --- a/src/particles/diagnostics/CovarianceMatrixMath.H +++ b/src/particles/diagnostics/CovarianceMatrixMath.H @@ -123,7 +123,7 @@ namespace impactx::diagnostics Complex Qc(Q,0.0_prt); Complex Rc(R,0.0_prt); Complex Dc(discriminant,0.0_prt); - Complex C = pow(-Rc + sqrt(Dc),1.0/3.0); + Complex C = amrex::pow(-Rc + amrex::sqrt(Dc),1.0/3.0); // Define a cubic root of unity xi amrex::ParticleReal xire = -1.0/2.0; @@ -142,7 +142,7 @@ namespace impactx::diagnostics Complex z1 = Qc/C - C; Complex z2 = Qc/(xi*C) - xi*C; - Complex z3 = Qc/(pow(xi,2)*C) - pow(xi,2)*C; + Complex z3 = Qc/(amrex::pow(xi,2)*C) - amrex::pow(xi,2)*C; x1 = z2.m_real - b/(3.0*a); x2 = z1.m_real - b/(3.0*a); x3 = z3.m_real - b/(3.0*a); From 534e40f087b7a18780aaff0fd10e08efcc7b51a1 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Wed, 2 Oct 2024 11:55:55 -0700 Subject: [PATCH 45/54] Avoid copying matrices --- src/particles/diagnostics/CovarianceMatrixMath.H | 6 +++--- src/particles/diagnostics/EmittanceInvariants.H | 4 ++-- src/particles/diagnostics/EmittanceInvariants.cpp | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/particles/diagnostics/CovarianceMatrixMath.H b/src/particles/diagnostics/CovarianceMatrixMath.H index 63aefd772..8771082ee 100644 --- a/src/particles/diagnostics/CovarianceMatrixMath.H +++ b/src/particles/diagnostics/CovarianceMatrixMath.H @@ -161,7 +161,7 @@ namespace impactx::diagnostics */ amrex::ParticleReal TraceMat ( - amrex::Array2D A + amrex::Array2D const & A ) { int const dim = 6; @@ -182,8 +182,8 @@ namespace impactx::diagnostics */ amrex::Array2D MultiplyMat ( - amrex::Array2D A, - amrex::Array2D B + amrex::Array2D const & A, + amrex::Array2D const & B ) { amrex::Array2D C; diff --git a/src/particles/diagnostics/EmittanceInvariants.H b/src/particles/diagnostics/EmittanceInvariants.H index 2d35db001..3766bd9a4 100644 --- a/src/particles/diagnostics/EmittanceInvariants.H +++ b/src/particles/diagnostics/EmittanceInvariants.H @@ -43,7 +43,7 @@ namespace impactx::diagnostics amrex::ParticleReal, amrex::ParticleReal> KineticInvariants ( - amrex::Array2D Sigma + amrex::Array2D const & Sigma ); /** Returns the three eigenemittances @@ -68,7 +68,7 @@ namespace impactx::diagnostics amrex::ParticleReal, amrex::ParticleReal> Eigenemittances ( - amrex::Array2D Sigma + amrex::Array2D const & Sigma ); } // namespace impactx::diagnostics diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index 397323c54..d8ab1daf5 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -37,7 +37,7 @@ namespace impactx::diagnostics amrex::ParticleReal, amrex::ParticleReal> KineticInvariants ( - amrex::Array2D Sigma + amrex::Array2D const & Sigma ) { using namespace amrex::literals; @@ -98,7 +98,7 @@ namespace impactx::diagnostics amrex::ParticleReal, amrex::ParticleReal> Eigenemittances ( - amrex::Array2D Sigma + amrex::Array2D const & Sigma ) { BL_PROFILE("impactx::diagnostics::Eigenemittances"); From ed52ed7558fb0fc600c5e8ff759ebc3aada56ad0 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Wed, 2 Oct 2024 11:57:09 -0700 Subject: [PATCH 46/54] Formatting: Whitespaces Only spaces --- examples/CMakeLists.txt | 4 +-- .../diagnostics/CovarianceMatrixMath.H | 26 +++++++++---------- .../diagnostics/EmittanceInvariants.H | 7 ++--- .../diagnostics/EmittanceInvariants.cpp | 13 +++++----- 4 files changed, 26 insertions(+), 24 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ce9f905f4..353743bff 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -965,13 +965,13 @@ add_impactx_test(dogleg.py # w/o space charge add_impactx_test(coupled-optics examples/coupled_optics/input_coupled_optics.in - ON # ImpactX MPI-parallel + ON # ImpactX MPI-parallel examples/coupled_optics/analysis_coupled_optics.py OFF # no plot script yet ) add_impactx_test(coupled-optics.py examples/coupled_optics/run_coupled_optics.py - OFF # ImpactX MPI-parallel + OFF # ImpactX MPI-parallel examples/coupled_optics/analysis_coupled_optics.py OFF # no plot script yet ) diff --git a/src/particles/diagnostics/CovarianceMatrixMath.H b/src/particles/diagnostics/CovarianceMatrixMath.H index 8771082ee..d90c9fc82 100644 --- a/src/particles/diagnostics/CovarianceMatrixMath.H +++ b/src/particles/diagnostics/CovarianceMatrixMath.H @@ -35,9 +35,10 @@ namespace impactx::diagnostics * @returns tuple of three real roots */ std::tuple< - amrex::ParticleReal, - amrex::ParticleReal, - amrex::ParticleReal> + amrex::ParticleReal, + amrex::ParticleReal, + amrex::ParticleReal + > CubicRootsTrig ( amrex::ParticleReal a, amrex::ParticleReal b, @@ -48,7 +49,7 @@ namespace impactx::diagnostics using namespace amrex::literals; using ablastr::constant::math::pi; - std::tuple roots; + std::tuple roots; amrex::ParticleReal x1 = 0.0_prt; amrex::ParticleReal x2 = 0.0_prt; amrex::ParticleReal x3 = 0.0_prt; @@ -59,11 +60,11 @@ namespace impactx::diagnostics // Discriminant should be < 0. Otherwise, keep theta at default and throw an error. amrex::ParticleReal tol = 1.0e-12; //allow for roundoff error - if(discriminant > tol){ + if (discriminant > tol) { std::cout << "Polynomial in CubicRoots has one or more complex roots." << "\n"; - } else if (Q == 0.0_prt){ // Special case of a triple root + } else if (Q == 0.0_prt) { // Special case of a triple root x1 = - b/(3.0_prt*a); x2 = - b/(3.0_prt*a); @@ -79,7 +80,6 @@ namespace impactx::diagnostics } - roots = std::make_tuple(x1,x2,x3); return roots; } @@ -97,9 +97,10 @@ namespace impactx::diagnostics * @returns tuple of three real roots */ std::tuple< - amrex::ParticleReal, - amrex::ParticleReal, - amrex::ParticleReal> + amrex::ParticleReal, + amrex::ParticleReal, + amrex::ParticleReal + > CubicRootsAlg ( amrex::ParticleReal a, amrex::ParticleReal b, @@ -110,7 +111,7 @@ namespace impactx::diagnostics using namespace amrex::literals; using Complex = amrex::GpuComplex; - std::tuple roots; + std::tuple roots; amrex::ParticleReal x1 = 0.0_prt; amrex::ParticleReal x2 = 0.0_prt; amrex::ParticleReal x3 = 0.0_prt; @@ -132,7 +133,7 @@ namespace impactx::diagnostics //Three roots in algebraic form. - if (C.m_real == 0.0_prt && C.m_imag == 0.0_prt){ // Special case of a triple root + if (C.m_real == 0.0_prt && C.m_imag == 0.0_prt) { // Special case of a triple root x1 = - b/(3.0_prt*a); x2 = - b/(3.0_prt*a); @@ -148,7 +149,6 @@ namespace impactx::diagnostics x3 = z3.m_real - b/(3.0*a); } - roots = std::make_tuple(x1,x2,x3); return roots; } diff --git a/src/particles/diagnostics/EmittanceInvariants.H b/src/particles/diagnostics/EmittanceInvariants.H index 3766bd9a4..177371953 100644 --- a/src/particles/diagnostics/EmittanceInvariants.H +++ b/src/particles/diagnostics/EmittanceInvariants.H @@ -39,9 +39,10 @@ namespace impactx::diagnostics * @returns tuple containing invariants I2, I4, and I6 */ std::tuple< - amrex::ParticleReal, - amrex::ParticleReal, - amrex::ParticleReal> + amrex::ParticleReal, + amrex::ParticleReal, + amrex::ParticleReal + > KineticInvariants ( amrex::Array2D const & Sigma ); diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index d8ab1daf5..51a276edc 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -33,9 +33,10 @@ namespace impactx::diagnostics * returns - tuple containing invarants I2, I4, and I6 */ std::tuple< - amrex::ParticleReal, - amrex::ParticleReal, - amrex::ParticleReal> + amrex::ParticleReal, + amrex::ParticleReal, + amrex::ParticleReal + > KineticInvariants ( amrex::Array2D const & Sigma ) @@ -105,9 +106,9 @@ namespace impactx::diagnostics using namespace amrex::literals; - std::tuple invariants; - std::tuple roots; - std::tuple emittances; + std::tuple invariants; + std::tuple roots; + std::tuple emittances; // Get the invariants I2, I4, and I6 from the covariance matrix. invariants = KineticInvariants(Sigma); From b922bb49a544e74cb1dc629e7d1d3f7ed082a804 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Wed, 2 Oct 2024 12:16:08 -0700 Subject: [PATCH 47/54] More general odd-ness test --- src/particles/diagnostics/EmittanceInvariants.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/particles/diagnostics/EmittanceInvariants.cpp b/src/particles/diagnostics/EmittanceInvariants.cpp index 51a276edc..20c6df32a 100644 --- a/src/particles/diagnostics/EmittanceInvariants.cpp +++ b/src/particles/diagnostics/EmittanceInvariants.cpp @@ -59,7 +59,7 @@ namespace impactx::diagnostics // a change of sign. for (int i = 1; i < 7; i++) { for (int j = 1; j < 7; j++) { - if (j % 2 == 1) { + if (j % 2 != 0) { S1(i,j) = -Sigma(i,j+1); // if j is odd } else { From 41bee2b6e8cee4ad3c965ecf21244ad366e5efad Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Sat, 5 Oct 2024 00:03:06 -0700 Subject: [PATCH 48/54] Add conditional emittance output columns. --- .../diagnostics/DiagnosticOutput.cpp | 56 ++++++++++++++++++- .../ReducedBeamCharacteristics.cpp | 26 ++++++--- 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/src/particles/diagnostics/DiagnosticOutput.cpp b/src/particles/diagnostics/DiagnosticOutput.cpp index 170b09a3f..c3cc93bf6 100644 --- a/src/particles/diagnostics/DiagnosticOutput.cpp +++ b/src/particles/diagnostics/DiagnosticOutput.cpp @@ -43,7 +43,14 @@ namespace impactx::diagnostics if (otype == OutputType::PrintRefParticle) { file_handler << "step s beta gamma beta_gamma x y z t px py pz pt\n"; } else if (otype == OutputType::PrintReducedBeamCharacteristics) { - file_handler << "step" << " " << "s" << " " + + // determine whether to output eigenemittances + amrex::ParmParse pp_diag("diag"); + bool compute_eigenemittances = false; + pp_diag.queryAdd("eigenemittances", compute_eigenemittances); + + if (compute_eigenemittances) { + file_handler << "step" << " " << "s" << " " << "x_mean" << " " << "x_min" << " " << "x_max" << " " << "y_mean" << " " << "y_min" << " " << "y_max" << " " << "t_mean" << " " << "t_min" << " " << "t_max" << " " @@ -57,9 +64,29 @@ namespace impactx::diagnostics << "beta_x" << " " << "beta_y" << " " << "beta_t" << " " << "dispersion_x" << " " << "dispersion_px" << " " << "dispersion_y" << " " << "dispersion_py" << " " + << "emittance_xn" << " " << "emittance_yn" << " " << "emittance_tn" << " " << "emittance_1" << " " << "emittance_2" << " " << "emittance_3" << " " << "charge_C" << " " << "\n"; + } else { + file_handler << "step" << " " << "s" << " " + << "x_mean" << " " << "x_min" << " " << "x_max" << " " + << "y_mean" << " " << "y_min" << " " << "y_max" << " " + << "t_mean" << " " << "t_min" << " " << "t_max" << " " + << "sig_x" << " " << "sig_y" << " " << "sig_t" << " " + << "px_mean" << " " << "px_min" << " " << "px_max" << " " + << "py_mean" << " " << "py_min" << " " << "py_max" << " " + << "pt_mean" << " " << "pt_min" << " " << "pt_max" << " " + << "sig_px" << " " << "sig_py" << " " << "sig_pt" << " " + << "emittance_x" << " " << "emittance_y" << " " << "emittance_t" << " " + << "alpha_x" << " " << "alpha_y" << " " << "alpha_t" << " " + << "beta_x" << " " << "beta_y" << " " << "beta_t" << " " + << "dispersion_x" << " " << "dispersion_px" << " " + << "dispersion_y" << " " << "dispersion_py" << " " + << "emittance_xn" << " " << "emittance_yn" << " " << "emittance_tn" << " " + << "charge_C" << " " + << "\n"; + } } } @@ -93,7 +120,13 @@ namespace impactx::diagnostics amrex::ParticleReal const s = pc.GetRefParticle().s; - file_handler << step << " " << s << " " + // determine whether to output eigenemittances + amrex::ParmParse pp_diag("diag"); + bool compute_eigenemittances = false; + pp_diag.queryAdd("eigenemittances", compute_eigenemittances); + + if (compute_eigenemittances) { + file_handler << step << " " << s << " " << rbc.at("x_mean") << " " << rbc.at("x_min") << " " << rbc.at("x_max") << " " << rbc.at("y_mean") << " " << rbc.at("y_min") << " " << rbc.at("y_max") << " " << rbc.at("t_mean") << " " << rbc.at("t_min") << " " << rbc.at("t_max") << " " @@ -107,8 +140,27 @@ namespace impactx::diagnostics << rbc.at("beta_x") << " " << rbc.at("beta_y") << " " << rbc.at("beta_t") << " " << rbc.at("dispersion_x") << " " << rbc.at("dispersion_px") << " " << rbc.at("dispersion_y") << " " << rbc.at("dispersion_py") << " " + << rbc.at("emittance_xn") << " " << rbc.at("emittance_yn") << " " << rbc.at("emittance_tn") << " " << rbc.at("emittance_1") << " " << rbc.at("emittance_2") << " " << rbc.at("emittance_3") << " " << rbc.at("charge_C") << "\n"; + } else { + file_handler << step << " " << s << " " + << rbc.at("x_mean") << " " << rbc.at("x_min") << " " << rbc.at("x_max") << " " + << rbc.at("y_mean") << " " << rbc.at("y_min") << " " << rbc.at("y_max") << " " + << rbc.at("t_mean") << " " << rbc.at("t_min") << " " << rbc.at("t_max") << " " + << rbc.at("sig_x") << " " << rbc.at("sig_y") << " " << rbc.at("sig_t") << " " + << rbc.at("px_mean") << " " << rbc.at("px_min") << " " << rbc.at("px_max") << " " + << rbc.at("py_mean") << " " << rbc.at("py_min") << " " << rbc.at("py_max") << " " + << rbc.at("pt_mean") << " " << rbc.at("pt_min") << " " << rbc.at("pt_max") << " " + << rbc.at("sig_px") << " " << rbc.at("sig_py") << " " << rbc.at("sig_pt") << " " + << rbc.at("emittance_x") << " " << rbc.at("emittance_y") << " " << rbc.at("emittance_t") << " " + << rbc.at("alpha_x") << " " << rbc.at("alpha_y") << " " << rbc.at("alpha_t") << " " + << rbc.at("beta_x") << " " << rbc.at("beta_y") << " " << rbc.at("beta_t") << " " + << rbc.at("dispersion_x") << " " << rbc.at("dispersion_px") << " " + << rbc.at("dispersion_y") << " " << rbc.at("dispersion_py") << " " + << rbc.at("emittance_xn") << " " << rbc.at("emittance_yn") << " " << rbc.at("emittance_tn") << " " + << rbc.at("charge_C") << "\n"; + } } // if( otype == OutputType::PrintReducedBeamCharacteristics) // TODO: add as an option to the monitor element diff --git a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp index 7e1d6a203..a7b623beb 100644 --- a/src/particles/diagnostics/ReducedBeamCharacteristics.cpp +++ b/src/particles/diagnostics/ReducedBeamCharacteristics.cpp @@ -305,19 +305,22 @@ namespace impactx::diagnostics amrex::ParticleReal const alpha_y = - ypy_d / emittance_yd; amrex::ParticleReal const alpha_t = - tpt / emittance_t; - // Calculate eigenemittances (optional) - amrex::Array2D Sigma; - amrex::ParticleReal emittance_1 = emittance_x * bg; - amrex::ParticleReal emittance_2 = emittance_y * bg; - amrex::ParticleReal emittance_3 = emittance_t * bg; + // Calculate normalized emittances + amrex::ParticleReal emittance_xn = emittance_x * bg; + amrex::ParticleReal emittance_yn = emittance_y * bg; + amrex::ParticleReal emittance_tn = emittance_t * bg; - // Parse the diagnostic parameters + // Determine whether to calculate eigenemittances, and initialize amrex::ParmParse pp_diag("diag"); bool compute_eigenemittances = false; pp_diag.queryAdd("eigenemittances", compute_eigenemittances); + amrex::ParticleReal emittance_1 = emittance_xn; + amrex::ParticleReal emittance_2 = emittance_yn; + amrex::ParticleReal emittance_3 = emittance_tn; if (compute_eigenemittances) { // Store the covariance matrix in dynamical variables: + amrex::Array2D Sigma; Sigma(1,1) = x_ms; Sigma(1,2) = xpx * bg; Sigma(1,3) = xy; @@ -400,9 +403,14 @@ namespace impactx::diagnostics data["dispersion_y"] = dispersion_y; data["dispersion_py"] = dispersion_py; data["charge_C"] = charge; - data["emittance_1"] = emittance_1; - data["emittance_2"] = emittance_2; - data["emittance_3"] = emittance_3; + data["emittance_xn"] = emittance_xn; + data["emittance_yn"] = emittance_yn; + data["emittance_tn"] = emittance_tn; + if (compute_eigenemittances) { + data["emittance_1"] = emittance_1; + data["emittance_2"] = emittance_2; + data["emittance_3"] = emittance_3; + } return data; } From e27c30eee24d2affca3515a1ae94375e39856787 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 5 Oct 2024 08:31:46 +0000 Subject: [PATCH 49/54] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/particles/diagnostics/DiagnosticOutput.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/particles/diagnostics/DiagnosticOutput.cpp b/src/particles/diagnostics/DiagnosticOutput.cpp index c3cc93bf6..1ec35610f 100644 --- a/src/particles/diagnostics/DiagnosticOutput.cpp +++ b/src/particles/diagnostics/DiagnosticOutput.cpp @@ -73,14 +73,14 @@ namespace impactx::diagnostics << "x_mean" << " " << "x_min" << " " << "x_max" << " " << "y_mean" << " " << "y_min" << " " << "y_max" << " " << "t_mean" << " " << "t_min" << " " << "t_max" << " " - << "sig_x" << " " << "sig_y" << " " << "sig_t" << " " + << "sig_x" << " " << "sig_y" << " " << "sig_t" << " " << "px_mean" << " " << "px_min" << " " << "px_max" << " " << "py_mean" << " " << "py_min" << " " << "py_max" << " " << "pt_mean" << " " << "pt_min" << " " << "pt_max" << " " - << "sig_px" << " " << "sig_py" << " " << "sig_pt" << " " + << "sig_px" << " " << "sig_py" << " " << "sig_pt" << " " << "emittance_x" << " " << "emittance_y" << " " << "emittance_t" << " " << "alpha_x" << " " << "alpha_y" << " " << "alpha_t" << " " - << "beta_x" << " " << "beta_y" << " " << "beta_t" << " " + << "beta_x" << " " << "beta_y" << " " << "beta_t" << " " << "dispersion_x" << " " << "dispersion_px" << " " << "dispersion_y" << " " << "dispersion_py" << " " << "emittance_xn" << " " << "emittance_yn" << " " << "emittance_tn" << " " @@ -148,14 +148,14 @@ namespace impactx::diagnostics << rbc.at("x_mean") << " " << rbc.at("x_min") << " " << rbc.at("x_max") << " " << rbc.at("y_mean") << " " << rbc.at("y_min") << " " << rbc.at("y_max") << " " << rbc.at("t_mean") << " " << rbc.at("t_min") << " " << rbc.at("t_max") << " " - << rbc.at("sig_x") << " " << rbc.at("sig_y") << " " << rbc.at("sig_t") << " " + << rbc.at("sig_x") << " " << rbc.at("sig_y") << " " << rbc.at("sig_t") << " " << rbc.at("px_mean") << " " << rbc.at("px_min") << " " << rbc.at("px_max") << " " << rbc.at("py_mean") << " " << rbc.at("py_min") << " " << rbc.at("py_max") << " " << rbc.at("pt_mean") << " " << rbc.at("pt_min") << " " << rbc.at("pt_max") << " " - << rbc.at("sig_px") << " " << rbc.at("sig_py") << " " << rbc.at("sig_pt") << " " + << rbc.at("sig_px") << " " << rbc.at("sig_py") << " " << rbc.at("sig_pt") << " " << rbc.at("emittance_x") << " " << rbc.at("emittance_y") << " " << rbc.at("emittance_t") << " " << rbc.at("alpha_x") << " " << rbc.at("alpha_y") << " " << rbc.at("alpha_t") << " " - << rbc.at("beta_x") << " " << rbc.at("beta_y") << " " << rbc.at("beta_t") << " " + << rbc.at("beta_x") << " " << rbc.at("beta_y") << " " << rbc.at("beta_t") << " " << rbc.at("dispersion_x") << " " << rbc.at("dispersion_px") << " " << rbc.at("dispersion_y") << " " << rbc.at("dispersion_py") << " " << rbc.at("emittance_xn") << " " << rbc.at("emittance_yn") << " " << rbc.at("emittance_tn") << " " From 4f2d689dec368944708c85c81084e63c537c0b63 Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Sat, 5 Oct 2024 02:48:57 -0700 Subject: [PATCH 50/54] Add documentation for user-facing input control. --- docs/source/usage/parameters.rst | 8 ++++++-- docs/source/usage/python.rst | 7 +++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/source/usage/parameters.rst b/docs/source/usage/parameters.rst index d21b1f2ab..9d3204b52 100644 --- a/docs/source/usage/parameters.rst +++ b/docs/source/usage/parameters.rst @@ -683,8 +683,8 @@ Diagnostics and output This option is ignored for the openPMD output elements (remove them from the lattice to disable). * ``diag.slice_step_diagnostics`` (``boolean``, optional, default: ``false``) - By default, diagnostics is performed at the beginning and end of the simulation. - Enabling this flag will write diagnostics every step and slice step + By default, diagnostics are computed and written at the beginning and end of the simulation. + Enabling this flag will write diagnostics at every step and slice step. * ``diag.file_min_digits`` (``integer``, optional, default: ``6``) The minimum number of digits used for the step number appended to the diagnostic file names. @@ -694,6 +694,10 @@ Diagnostics and output Diagnostics for particles lost in apertures, stored as ``diags/openPMD/particles_lost.*`` at the end of the simulation. See the ``beam_monitor`` element for backend values. +* ``diag.eigenemittances`` (``boolean``, optional, default: ``false``) + If this flag is enabled, the 3 eigenemittances of the 6D beam distribution are computed and written as diagnostics. + This flag is disabled by default to reduce computational cost. + .. _running-cpp-parameters-diagnostics-insitu: diff --git a/docs/source/usage/python.rst b/docs/source/usage/python.rst index 52acfe210..2a27cb5b9 100644 --- a/docs/source/usage/python.rst +++ b/docs/source/usage/python.rst @@ -156,6 +156,13 @@ Collective Effects & Overall Simulation Parameters Diagnostics for particles lost in apertures. See the ``BeamMonitor`` element for backend values. + .. py:property:: eigenemittances + + Enable (``True``) or disable (``False``) output of eigenemittances at every slice step in elements (default: ``False``). + + If this flag is enabled, the 3 eigenemittances of the 6D beam distribution are computed and written as diagnostics. + This flag is disabled by default to reduce computational cost. + .. py:method:: init_grids() Initialize AMReX blocks/grids for domain decomposition & space charge mesh. From d8128ac856d0d705c336d363e9409560bd15a477 Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Sat, 5 Oct 2024 12:02:14 +0200 Subject: [PATCH 51/54] Update dataanalysis documentation of eigenemittances. --- docs/source/dataanalysis/dataanalysis.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/source/dataanalysis/dataanalysis.rst b/docs/source/dataanalysis/dataanalysis.rst index 6bc551c10..cc170b57a 100644 --- a/docs/source/dataanalysis/dataanalysis.rst +++ b/docs/source/dataanalysis/dataanalysis.rst @@ -84,7 +84,7 @@ The code writes out the values in an ASCII file prefixed ``reduced_beam_characte * ``sig_px``, ``sig_py``, ``sig_pt`` Standard deviation of the particle momentum deviations (energy difference for ``pt``) normalized by the magnitude of the reference particle momentum (unit: dimensionless) * ``emittance_x``, ``emittance_y``, ``emittance_t`` - Normalized rms beam emittance (unit: meter) + Unnormalized rms beam emittances (unit: meter) * ``alpha_x``, ``alpha_y``, ``alpha_t`` Courant-Snyder (Twiss) alpha (unit: dimensionless). Transverse Twiss functions are calculated after removing correlations with particle energy. * ``beta_x``, ``beta_y``, ``beta_t`` @@ -93,8 +93,11 @@ The code writes out the values in an ASCII file prefixed ``reduced_beam_characte Horizontal and vertical dispersion (unit: meter) * ``dispersion_px``, ``dispersion_py`` Derivative of horizontal and vertical dispersion (unit: dimensionless) +* ``emittance_xn``, ``emittance_yn``, ``emittance_tn`` + Normalized rms beam emittances (unit: meter) * ``emittance_1``, ``emittance_2``, ``emittance_3`` Normalized rms beam eigenemittances (aka mode emittances) (unit: meter) + These three diagnostics are written optionally if the flag eigenemittances = True. * ``charge`` Total beam charge (unit: Coulomb) From 4b8f7b3bad8ad121bd0d4df6ca36cf66c1e26d17 Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Tue, 8 Oct 2024 11:43:04 -0700 Subject: [PATCH 52/54] Update CovarianceMatrixMath.H Update treatment of warnings. --- src/particles/diagnostics/CovarianceMatrixMath.H | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/particles/diagnostics/CovarianceMatrixMath.H b/src/particles/diagnostics/CovarianceMatrixMath.H index d90c9fc82..a3b0099cf 100644 --- a/src/particles/diagnostics/CovarianceMatrixMath.H +++ b/src/particles/diagnostics/CovarianceMatrixMath.H @@ -11,6 +11,7 @@ #define COVARIANCE_MATRIX_MATH_H #include +#include #include #include @@ -62,6 +63,15 @@ namespace impactx::diagnostics amrex::ParticleReal tol = 1.0e-12; //allow for roundoff error if (discriminant > tol) { + ablastr::warn_manager::WMRecordWarning( + "Impactx::diagnostics::CubicRootsTrig", + "Polynomial appearing in CubicRootsTrig has one or more complex " + "(non-real) roots. Only the real part is returned. This " + "suggests a loss of numerical precision in computation of the " + "eigenemittances. Treat eigenemittance values with caution.", + ablastr::warn_manager::WarnPriority::medium + ); + std::cout << "Polynomial in CubicRoots has one or more complex roots." << "\n"; } else if (Q == 0.0_prt) { // Special case of a triple root From 6d61630b43a80accc6ebec8d57bb22b0ef055974 Mon Sep 17 00:00:00 2001 From: Chad Mitchell <46825199+cemitch99@users.noreply.github.com> Date: Tue, 8 Oct 2024 11:51:06 -0700 Subject: [PATCH 53/54] Apply suggestions from code review Changes to test_transformation.py were not intentional. These were reversed per code review. Co-authored-by: Axel Huebl --- tests/python/test_transformation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/test_transformation.py b/tests/python/test_transformation.py index aa00b349c..93b52966c 100644 --- a/tests/python/test_transformation.py +++ b/tests/python/test_transformation.py @@ -81,7 +81,7 @@ def test_transformation(): for key, val in rbc_s0.items(): if not np.isclose(val, rbc_s[key], rtol=rtol, atol=atol): print(f"initial[{key}]={val}, final[{key}]={rbc_s[key]} not equal") - assert np.isclose(val, rbc_s[key], rtol=rtol, atol=atol) + assert np.isclose(val, rbc_s[key], rtol=rtol, atol=atol) # assert that the t-based beam is different, at least in the following keys: large_st_diff_keys = [ "beta_x", From 345f5b1c24e54a182727db7a32947ddf3438b59e Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Wed, 9 Oct 2024 20:51:02 -0700 Subject: [PATCH 54/54] Update tests/python/test_transformation.py --- tests/python/test_transformation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/test_transformation.py b/tests/python/test_transformation.py index 93b52966c..ad660564c 100644 --- a/tests/python/test_transformation.py +++ b/tests/python/test_transformation.py @@ -81,7 +81,7 @@ def test_transformation(): for key, val in rbc_s0.items(): if not np.isclose(val, rbc_s[key], rtol=rtol, atol=atol): print(f"initial[{key}]={val}, final[{key}]={rbc_s[key]} not equal") - assert np.isclose(val, rbc_s[key], rtol=rtol, atol=atol) + assert False # assert that the t-based beam is different, at least in the following keys: large_st_diff_keys = [ "beta_x",