Skip to content

Conversation

@lucafedeli88
Copy link
Member

@lucafedeli88 lucafedeli88 commented Apr 11, 2025

With this PR the constants in ablastr are first defined using variable templates and then specialized for amrex::Real, e.g., for mathematical constants:

    /** Mathematical constants */
    namespace math
    {
        //! ratio of a circle's circumference to its diameter (variable template)
        template<typename T>
        constexpr auto pi_v = static_cast<T>(3.14159265358979323846);

        //! https://tauday.com/tau-manifesto (variable template)
        template<typename T>
        constexpr auto tau_v = static_cast<T>(2.0 * pi_v<double>);

        //! ratio of a circle's circumference to its diameter
        constexpr auto pi = pi_v<amrex::Real>;

        //! https://tauday.com/tau-manifesto
        constexpr auto tau = tau_v<amrex::Real>;

    } // namespace math

This is done with the intent of allowing the use of double precision constants even if the code is compiled in single precision (or vice versa if you really want it !), e.g. :

const auto a = 2_rt * math::pi; // a is an amrex::Real

const auto b = 2 * math::pi_v<double>; // b is a double !

const auto c = 2 * math::pi_v<float>; // c is a float !

I will need this feature to import the QED module from PICSAR into WarpX. I've started migrating the code in #5677 ,but the PR is becoming too big, so I decided to split it into smaller chunks.

The new feature is now used in the template function Algorithms::KineticEnergy . This function is conceived to be able to force double precision in some cases regardless of how WarpX has been compiled. Therefore, using c in double precision in these cases is coherent with its goal.

Note that I've changed the variables from static constexpr to constexpr because, to my understanding, static does not make any difference in this context.

Previous discussions

With this PR the constants in ablastr are first defined using variable templates and then specialized for amrex::Real, e.g., for mathematical constants:

    namespace math
    {
        namespace variable_templates
        {

            template<typename T>
            constexpr auto pi = static_cast<T>(3.14159265358979323846);

            template<typename T>
            constexpr auto tau = static_cast<T>(2.0 * pi<double>);

        } 

        constexpr auto pi = variable_templates::pi<amrex::Real>;

        constexpr auto tau = variable_templates::tau<amrex::Real>;

    } // namespace math

This is done with the intent of allowing the use of double precision constants even if the code is compiled in single precision (or vice versa if you really want it !), e.g. :

using namespace ablastr;
namespace math_vt = math::variable_templates;

const auto a = 2_rt * math::pi; // a is an amrex::Real

const auto b = 2 * math_vt::pi<double>; // b is a double !

I will need this feature to import the QED module from PICSAR into WarpX. I've started migrating the code in #5677 ,but the PR is becoming too big, so I decided to split it into smaller chunks.

The new feature is now used in the template function Algorithms::KineticEnergy . This function is conceived to be able to force double precision in some cases regardless of how WarpX has been compiled. Therefore, using c in double precision in these cases is coherent with its goal.

In case you don't like the long namespace name variable_template, an alternative would be to call it vt.

Note that I've changed the variables from static constexpr to constexpr because, to my understanding, static does not make any difference in this context.

Updates

@lucafedeli88 lucafedeli88 added the component: ABLASTR components shared with other PIC codes label Apr 11, 2025
@lucafedeli88 lucafedeli88 requested review from EZoni and RemiLehe April 11, 2025 14:09
@lucafedeli88 lucafedeli88 changed the title Ablastr constants : add variable templates to allow for flexibility in using different precisions for constants Ablastr constants : add variable templates to allow for flexibility in using different precisions Apr 11, 2025
@lucafedeli88 lucafedeli88 changed the title Ablastr constants : add variable templates to allow for flexibility in using different precisions Ablastr constants : add variable templates to allow for flexibility in using single/double precision Apr 11, 2025
@lucafedeli88 lucafedeli88 changed the title Ablastr constants : add variable templates to allow for flexibility in using single/double precision ablastr constants : add variable templates to allow for flexibility in using single/double precision Apr 11, 2025
namespace math
{
using namespace amrex::literals;
namespace variable_templates
Copy link
Member

Choose a reason for hiding this comment

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

Since this is for constants, perhaps call it constant_templates?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sorry for not having replied earlier, @dpgrote !
Would const_templates work according to you?

Copy link
Member

Choose a reason for hiding this comment

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

Thanks, it's better, but const has a specific meaning in C++ so that could cause confusion.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think that you are right, @dpgrote . I've changed the name to constant_templates, as you originally suggested.

@EZoni EZoni requested review from WeiqunZhang and atmyers April 15, 2025 23:49
@EZoni EZoni self-assigned this Apr 15, 2025
@lucafedeli88 lucafedeli88 requested a review from dpgrote May 7, 2025 08:10
@dpgrote
Copy link
Member

dpgrote commented May 7, 2025

Would there be much penalty if the constants were all explicitly declared double? This might generate warnings of explicit down casting when single precision is being used, but would there be a performance penalty?

@lucafedeli88
Copy link
Member Author

Would there be much penalty if the constants were all explicitly declared double? This might generate warnings of explicit down casting when single precision is being used, but would there be a performance penalty?

The main issue I see is that, due to our extensive use of the auto keyword, inserting just one constant in double precision may silently transform whole blocks of calculations to double precision. I am afraid that this might have an impact on performances. What I like of the approach followed in this PR is that everything works as before unless you specifically want your constants with a given precision. The verbosity of constant_templates is a feature: you only use it when you really need it!

@aeriforme
Copy link
Member

aeriforme commented May 13, 2025

We make massive and inconsistent use of $c^{-2}, c^{-1}, c^2$ and similar.
Should we add them here, so that we don't have to re-calculate them every time?

@lucafedeli88
Copy link
Member Author

We make massive and inconsistent use of c − 2 , c − 1 , c 2 and similar. Should we add them here, so that we don't have to re-calculate them every time?

We often use constexpr when we define these constants in the code, so this should not result into an overhead.
However, we can consider adding these constants.

@lucafedeli88
Copy link
Member Author

We make massive and inconsistent use of c − 2 , c − 1 , c 2 and similar. Should we add them here, so that we don't have to re-calculate them every time?

@aeriforme , I've added c2, invc, and invc2 constants, and I have tested them by modifying a couple of source files. If we like the new constants we can use them everywhere in WarpX, maybe by making the change with another PR.

@lucafedeli88
Copy link
Member Author

ping, @aeriforme ;-)

Copy link
Member

@EZoni EZoni left a comment

Choose a reason for hiding this comment

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

Thanks for the PR, @lucafedeli88! I left only a couple of minor comments.

namespace math
{
using namespace amrex::literals;
namespace constant_templates
Copy link
Member

@EZoni EZoni May 27, 2025

Choose a reason for hiding this comment

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

I'm wondering whether we could drop the templates part in the name...

Obviously it does describe what this is, as far as the implementation is concerned, but from the perspective of this being used in the code I wonder if PhysConst::constant_templates::invc2<amrex::Real> is really "needed", as opposed to, say, simply PhysConst::constants::invc2<amrex::Real>?

Copy link
Member Author

Choose a reason for hiding this comment

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

@EZoni , what about an abbreviation, such as tmpl (constant is already in PhysConst):
e.g.
PhysConst::tmpl::invc2<amrex::Real>

?

Copy link
Member

Choose a reason for hiding this comment

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

Hm, I think I'm a bit confused. Can we try to summarize all namespaces we have currently in development?

I'm seeing

namespace MathConst
{
using namespace ablastr::constant::math;
}
namespace PhysConst
{
using namespace ablastr::constant::SI;
}

and also

namespace ablastr::constant
{
/** Mathematical constants */
namespace math
{
using namespace amrex::literals;
//! ratio of a circle's circumference to its diameter
static constexpr amrex::Real pi = 3.14159265358979323846_rt;
//! https://tauday.com/tau-manifesto
static constexpr amrex::Real tau = 2.0_rt * pi;
} // namespace math
/** Physical constants
*
* Values are the 2022 CODATA recommended values
* https://physics.nist.gov/cuu/Constants/index.html
*
* New additions here should also be considered for addition to
* `warpx_constants` in WarpXUtil.cpp's `makeParser`, so that they're
* available in parsing and evaluation of PICMI expressions, as well
* as the corresponding Python definitions
*/
namespace SI
{
using namespace amrex::literals;
//! vacuum speed of light [m/s]
static constexpr auto c = 299'792'458._rt;
//! vacuum permittivity: dielectric permittivity of vacuum [F/m]
static constexpr auto ep0 = 8.8541878188e-12_rt;
//! vacuum permeability: magnetic permeability of vacuum = 4.0e-7 * pi [H/m]
//! Note that this is adjusted from the CODATA2022 value, 1.25663706127e-06
//! So that the relation between mu0, ep0, and c is exact.
static constexpr auto mu0 = 1.2566370612685e-06_rt;
//! elementary charge [C]
static constexpr auto q_e = 1.602176634e-19_rt;
//! electron mass [kg]
static constexpr auto m_e = 9.1093837139e-31_rt;
//! proton mass [kg]
static constexpr auto m_p = 1.67262192595e-27_rt;
//! dalton: unified atomic mass unit [kg]
static constexpr auto m_u = 1.66053906892e-27_rt;
//! reduced Planck Constant = h / tau [J*s]
static constexpr auto hbar = 1.0545718176461565e-34_rt;
//! fine-structure constant = mu0/(4*pi)*q_e*q_e*c/hbar [dimensionless]
//! The value is calculated from the expression. This differs
//! slightly from the CODATA2022 value 0.0072973525643.
static constexpr auto alpha = 0.0072973525643330135_rt;
//! classical electron radius = 1./(4*pi*ep0) * q_e*q_e/(m_e*c*c) [m]
static constexpr auto r_e = 2.8179403205e-15_rt;
//! xi: nonlinearity parameter of Heisenberg-Euler effective theory = (2.*alpha*alpha*ep0*ep0*hbar*hbar*hbar)/(45.*m_e*m_e*m_e*m_e*c*c*c*c*c)
static constexpr double xi = 1.3050122383827227e-52;
//! xi times c2 = xi*c*c. This should be usable for single precision instead of xi; very close to smallest float32 number possible (1.2e-38)
static constexpr auto xi_c2 = 1.1728865075613984e-35_rt;
//! Boltzmann constant (exact) [J/K]
static constexpr auto kb = 1.380649e-23_rt;
//! 1 eV in [J]
static constexpr auto eV = q_e;
//! 1 MeV in [J]
static constexpr auto MeV = q_e * 1e6_rt;
//! 1 eV/c in [kg*m/s]
static constexpr auto eV_invc = eV / c;
//! 1 MeV/c in [kg*m/s]
static constexpr auto MeV_invc = MeV / c;
//! 1 eV/c^2 in [kg]
static constexpr auto eV_invc2 = eV / (c * c);
//! 1 MeV/c^2 in [kg]
static constexpr auto MeV_invc2 = MeV / (c * c);
} // namespace SI
} // namespace ablastr::constant

So, we can do, e.g.,

PhysConst::c

but we cannot do

PhysConst::constant::c

right?

Where does the conflict with, say, PhysConst::constant::c<amrex::Real> (although I would use constants) come from? When I say "conflict" I refer to what you mentioned about constant being already in PhysConst.

Is the argument that PhysConst::constant_templates::c<amrex::Real> is more intuitive than PhysConst::constant::c<amrex::Real> because with the latter one doesn't immediately foresee that they should pass the template parameter?

Copy link
Member

Choose a reason for hiding this comment

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

@lucafedeli88

I think we are close to finalizing this PR, as long as we resolve the latest questions raised in #5828 (comment).

Copy link
Member Author

@lucafedeli88 lucafedeli88 Aug 8, 2025

Choose a reason for hiding this comment

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

Sorry for not having replied earlier, @EZoni !

If you have the nested namespace structure that we have in ablastr and WarpX you can do - and can't do - the following :

namespace ablastr::constant 
{ 
    namespace SI
    {
        constexpr double  c = 299792458.0;
    }
}

 namespace PhysConst 
 { 
     using namespace ablastr::constant::SI; 
 } 

void test ()
{
    auto ttA = ablastr::constant::SI::c;

    auto ttB = PhysConst::c;

    // ILLEGAL
    // auto ttC = c;
    // auto ttC = SI::c;
    // auto ttC = constant::SI::c;
    // auto ttC = PhysConst::SI::c;
    // auto ttC = PhysConst::constant::SI::c;
    // auto ttC = PhysConst::ablastr::constant::SI::c;
}

What you suggest can work if we do the following :

namespace ablastr::constant 
{ 
    namespace SI
    {
        namespace constants 
        {
            template <typename T>
            constexpr T c = static_cast<T>(299792458.0);
        }

        constexpr double  c = constants::c<double>;

    }
}

 namespace PhysConst 
 { 
     using namespace ablastr::constant::SI; 
 } 

void test ()
{
    auto ttA = PhysConst::c;

    auto ttB = PhysConst::constants::c<float>;
}

However, having ablastr::constant::SI::constants::c<T> disturbs me, since we confusingly repeat almost the same name in the nested namespace hierarchy. That's why I suggest something like :

ablastr::constant::SI::tmpl::c<T>

for templated constants .

What we can't do is having a template and a non-template constant with the same name in the same namespace.

I also considered setting a default template value, but we need to use the suffix <> to use it, which is not very practical !

template <typename T = double>
constexpr T c = static_cast<T>(299792458.0);

auto tt = c<>;

@lucafedeli88 lucafedeli88 requested a review from EZoni June 11, 2025 15:37
@WeiqunZhang
Copy link
Member

WeiqunZhang commented Aug 8, 2025

Why not following the C++ standard's approach? Once we start using C++20, it will also be easier to switch to std::numbers.

double a = PhysConst::c;
float b = PhysConst:c_v<float>;

https://en.cppreference.com/w/cpp/numeric/constants.html

@EZoni
Copy link
Member

EZoni commented Aug 14, 2025

@lucafedeli88

@WeiqunZhang's suggestion seems good to me, what do you think?

@lucafedeli88
Copy link
Member Author

It's a very good idea ! Sorry for my late answer, I've been away for vacation and for a conference, but I'll resume working on this PR very soon.

@lucafedeli88
Copy link
Member Author

lucafedeli88 commented Sep 15, 2025

@EZoni , I've just implemented @WeiqunZhang 's suggestion .

@lucafedeli88
Copy link
Member Author

Ping, @EZoni ;-) !

@EZoni EZoni self-requested a review September 22, 2025 22:49

//! vacuum permittivity: dielectric permittivity of vacuum [F/m] (variable template)
template<typename T>
constexpr auto ep0 = static_cast<T>(8.8541878188e-12);
Copy link
Member

Choose a reason for hiding this comment

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

Can we call it epsilon0 or, my favorite, epsilon_0?

Copy link
Member

Choose a reason for hiding this comment

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

I agree. SciPy's name is epsilon_0 - I would use the same.


//! vacuum permittivity: dielectric permittivity of vacuum [F/m]
static constexpr auto ep0 = 8.8541878188e-12_rt;
constexpr auto ep0 = constant_templates::ep0<amrex::Real>;
Copy link
Member

Choose a reason for hiding this comment

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

Same as above


//! reduced Planck Constant = h / tau [J*s]
static constexpr auto hbar = 1.0545718176461565e-34_rt;
constexpr auto hbar = hbar_v<amrex::Real>;
Copy link
Member

Choose a reason for hiding this comment

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

Is it possible that hbar is not exposed to the input file?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, it is not exposed at the moment. We probably should do that! It's a good idea for another PR, I think.


//! Schwinger field [V/m] (variable template)
template<typename T>
constexpr auto schwinger_field = schwinger_field_v<amrex::Real>;
Copy link
Member

Choose a reason for hiding this comment

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

Should we specify that it's E field?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, that's a good remark. I've updated the docstring.

static constexpr auto r_e = 2.8179403205e-15_rt;
//! xi: nonlinearity parameter of Heisenberg-Euler effective theory = (2.*alpha*alpha*ep0*ep0*hbar*hbar*hbar)/(45.*m_e*m_e*m_e*m_e*c*c*c*c*c)
static constexpr double xi = 1.3050122383827227e-52;
constexpr auto r_e = r_e_v<amrex::Real>;
Copy link
Member

Choose a reason for hiding this comment

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

Should we add the Compton wavelength?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think that we can. If it is already used in WarpX or if you plan to use it we should! However, I think that it is better if it is done in a different PR for clarity.

Copy link
Member

@ax3l ax3l left a comment

Choose a reason for hiding this comment

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

LGTM, thank you all!

@lucafedeli88 please address the three doc string comments by @aeriforme and then feel free to self-merge.

@EZoni
Copy link
Member

EZoni commented Oct 29, 2025

Note that there is also #5828 (comment) that isn't just about docstrings. We already changed other names in this PR, e.g., invc and invc2, so we could change ep0 too, as suggested by @aeriforme - to be discussed.

@lucafedeli88
Copy link
Member Author

Note that there is also #5828 (comment) that isn't just about docstrings. We already changed other names in this PR, e.g., invc and invc2, so we could change ep0 too, as suggested by @aeriforme - to be discussed.

I'll open a poll

@lucafedeli88 lucafedeli88 enabled auto-merge (squash) November 5, 2025 09:54
@lucafedeli88 lucafedeli88 merged commit 31eda89 into BLAST-WarpX:development Nov 5, 2025
50 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component: ABLASTR components shared with other PIC codes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants