Closed MilanSkocic closed 1 month ago
Thank you @MilanSkocic for this PR. I am not a user of such constants. So I will add a few possible reviewers.
A general question/comment is about the kinds provided. I think we should try to provide at least single and double precision (it should be easy with fypp
). But it is maybe useless (I don't know as I never use such things).
Just a style comment. Maybe instead of defining the actual value of the constants with real(7294.29954142d0,dp)
you could simply use 7294.29954142_dp
which already declares the kind from the parameter dp
, instead of asking for a conversion to the same kind.
Thank you @MilanSkocic for this PR. I am not a user of such constants. So I will add a few possible reviewers.
A general question/comment is about the kinds provided. I think we should try to provide at least single and double precision (it should be easy with
fypp
). But it is maybe useless (I don't know as I never use such things).
I have a dedicated repo for generating the constants for the stdlib (https://github.com/MilanSkocic/stdlib_codata) where I have tested single precisions. However, I've got overflows for some constants. I also have my package where I provided codata constants for 2018, 2014 and 2010.
In my point of view single precision are not relevant for the codata constants.
Just a style comment. Maybe instead of defining the actual value of the constants with
real(7294.29954142d0,dp)
you could simply use7294.29954142_dp
which already declares the kind from the parameterdp
, instead of asking for a conversion to the same kind.
Right! I will make the change as soon as possible.
This is a very interesting proposal @MilanSkocic. I have a comment that does not want to mandate any specifications, but just lay out ideas on how this could be made the most productive.
have looked at the state of the art as offered from other well-established packages: Scipy offers a full range of CODATA constants.
They're very easy to use because they're basically just numeric constants. So I think it would be most useful if stdlib
could also provide that facility. I think there are two ways to do it:
1) Implement all overloaded operators (==
, /=
, >
, <
, +
, -
, *
, **
, /
, etc.) so that these parameter
derived types can be used exactly as any other real
parameter. However, because they also contain units and other information (i.e. error), more tools could be available e.g. something like .approx.
to check whether a value is within the uncertainty bounds of the constant.
The drawback is you need to import all operators, not only the constant:
use stdlib_codata, only: ALPHA_PARTICLE_ELECTRON_MASS_RATIO, operator(+), operator(/), assignment(=), ...
2) Also provide a "macro-like" interface to each of them, so that they can also be used as a real
constant in code. for example:
interface gravitational_constant
module procedure g_sp
module procedure g_dp
...
end interface
!...
elemental real(dp) function g_dp(mold)
real(dp), intent(in), optional :: mold ! dp is the default kind
g_dp = real(NEWTONIAN_CONSTANT_OF_GRAVITATION%value, kind=dp)
end function g_dp
elemental real(dp) function g_sp(mold)
real(sp), intent(in) :: mold ! sp is not the default kind -> not optional
g_sp = real(NEWTONIAN_CONSTANT_OF_GRAVITATION%value, kind=sp)
ed function g_sp
!etc.
so one could use them like
real(dp) :: energy = h * gravitational_constant()
real(sp) :: nrg = h * gravitational_constant(mold=0.0)
Or maybe use the generic facility to avoid having to declare an interface for each constant? like this: https://godbolt.org/z/17qP4TWoa
the generic facility
It's definitely useful if this class has a few methods (including a nice print
, etc.). For the purpose of just returning the numeric value (and because there is no constexpr
in Fortran), I think a nice named interface is more readable IMHO.
Another option would be to override real
and do something like real(NEWTONIAN_CONSTANT_OF_GRAVITATION,kind=dp)
which is also Fortranic, but is too long in my opinion
@perazz You are right, in Scipy, some of the most common physical constants are available directly as reals. They are aliases to the values of the complete list of Codata constants which are implemented as a dictionary where keys are names and items are tuples containing the value, the uncertainty and the unit.
I can implement the codata constants as derived types with the generic facility as suggested by @jalvesz in a module called stdlib_codata
and add aliases to the values of the most common physical constants in a module called stdlib_constants
as it is done in Scipy. In the latter, mathematical constants, such as PI
(#99), could be added later.
An example of using the constants:
program test
! use of the aliases to the values of the most common codata constants and mathematical constants
use stdlib_constants, only: c, PI
! use of other codata constants
use stdlib_codata, only: ALPHA_PARTICLE_ELECTRON_MASS_RATIO
real :: b
b = ALPHA_PARTICLE_ELECTRON_MASS_RATIO%eval(b) ! generic facility
end program test
A more advanced use of the stdlib_codata
module would allow the user to directly initialize a parameter by accessing the value of the constant.
program test
use stdlib_codata, only: ALPHA_PARTICLE_ELECTRON_MASS_RATIO
use stdlib_kinds, only: dp
real(dp), parameter :: alpha = ALPHA_PARTICLE_ELECTRON_MASS_RATIO%value
end program test
Update based on suggestions from @perazz and @jalvesz:
stdlib_codata_type
. The actual auto-generated codata constants are isolated in the module stdlib_codata
stdlib_constants
where the most common physical constants are aliases to the values of the codata constants (mimic Scipy constant module).stdlib_constants
?Do I need to create the associated documentation in /docs/specs
?
I think that an example would be useful in the example
folder. Do you think that a dedicated subfolder constants
or codata
is necessary or the example can be placed in an already existing subfolder?
Do I need to create the associated documentation in
/docs/specs
?
Yes, please. It could be called stdlib_constants.md
I think that an example would be useful in the
example
folder. Do you think that a dedicated subfolderconstants
orcodata
is necessary or the example can be placed in an already existing subfolder?
It should be in a dedicated subfolder, e.g., constants
.
I have added the documentation and the example.
@perazz to_real
for consistency with stdlib has been added.
Thank you @MilanSkocic for this PR. I think it is close to be merged. Here are some minor comments. Could you maybe also add some tests? At least for the DR?
No problem the tests. I was already working on.
The code for autogenerating the stdlib_codata
module is available here. It is a simple parser written in Python of the raw data provided by the NIST. If needed it can be incorporated in stdlib.
I added tests for some Codata constants (values and uncertainties) that I have arbitrary chosen.
I did not implement any test for mathematical constants as I have only defined one (PI). I am not sure how the mathematical constants should be implemented i.e. either the way I did or through derived type as mentioned issue #99.
@jvdp1 Let me know if you want me to remove the mathematical constant PI
until a definitive decision is made.
Could you also rebase your code to solve the conflicts, please?
No problem @jvdp1 . I will take into account all your comments and suggestions. I will solve the conflicts and I will let you know when it is done.
Sorry. I though it was always the same value. If not, it should not be a module variable because the tests can be run in parallel. Could it be a mix of the two approaches?
Le dim. 19 mai 2024, 07:38, Milan Skocic @.***> a écrit :
@.**** commented on this pull request.
In test/constants/test_constants.f90 https://github.com/fortran-lang/stdlib/pull/800#discussion_r1605951192:
- implicit none
- type(error_type), allocatable, intent(out) :: error
- real(dp) :: value, expected, diff, fac
- fac = 1.0d0
- expected = 0.0d0 * fac
- value = SPEED_OF_LIGHT_IN_VACUUM%to_real(fac, uncertainty=.true.) * fac
- diff = expected - value
- call check(error, diff, 0.0d0)
- if (allocated(error)) return +end subroutine
+subroutine test_U_STANDARD_ACCELERATION_OF_GRAVITY(error)
- implicit none
- type(error_type), allocatable, intent(out) :: error
- real(dp) :: value, expected, diff, fac
- fac = 1.0d0
I changed fac as a module level variable. I did not declare it as a parameter because I need to able to change according to the values that are being tested.
— Reply to this email directly, view it on GitHub https://github.com/fortran-lang/stdlib/pull/800#discussion_r1605951192, or unsubscribe https://github.com/notifications/unsubscribe-auth/AD5RO7EE4AY2HZ3N6CO767TZDA3HHAVCNFSM6AAAAABGRC7NM6VHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZDANRUHE4TOMZSGA . You are receiving this because you were mentioned.Message ID: @.***>
Sorry. I though it was always the same value. If not, it should not be a
module variable because the tests can be run in parallel.
Could it be a mix of the two approaches?
Le dim. 19 mai 2024, 07:38, Milan Skocic @.***> a
écrit :
@.**** commented on this pull request.
In test/constants/test_constants.f90
https://github.com/fortran-lang/stdlib/pull/800#discussion_r1605951192:
- implicit none
type(error_type), allocatable, intent(out) :: error
real(dp) :: value, expected, diff, fac
fac = 1.0d0
expected = 0.0d0 * fac
value = SPEED_OF_LIGHT_IN_VACUUM%to_real(fac, uncertainty=.true.) * fac
diff = expected - value
call check(error, diff, 0.0d0)
if (allocated(error)) return
+end subroutine
+
+subroutine test_U_STANDARD_ACCELERATION_OF_GRAVITY(error)
implicit none
type(error_type), allocatable, intent(out) :: error
real(dp) :: value, expected, diff, fac
fac = 1.0d0
I changed fac as a module level variable. I did not declare it as a
parameter because I need to able to change according to the values that are
being tested.
—
Reply to this email directly, view it on GitHub
https://github.com/fortran-lang/stdlib/pull/800#discussion_r1605951192,
or unsubscribe
.
You are receiving this because you were mentioned.Message ID:
@.***>
No problem.
@jvdp1
Faire point @perazz
I will not be a user of such data. But i think that they should be kept in stdlib. Both notations are fine for me
Le mar. 21 mai 2024, 17:43, Federico Perini @.***> a écrit :
@.**** commented on this pull request.
In src/stdlib_constants.fypp https://github.com/fortran-lang/stdlib/pull/800#discussion_r1608552969:
- STEFAN_BOLTZMANN_CONSTANT, &
- WIEN_WAVELENGTH_DISPLACEMENT_LAW_CONSTANT, &
- RYDBERG_CONSTANT, &
- ELECTRON_MASS, &
- PROTON_MASS, &
- NEUTRON_MASS, &
- ATOMIC_MASS_CONSTANT
- private
- ! mathematical constants
:for k in KINDS
- real(${k}$), parameter, public :: PI${k}$ = acos(-1.0${k}$) !! PI
:endfor
- ! Physical constants
- real(dp), parameter, public :: c = SPEED_OF_LIGHT_IN_VACUUM%value !! Speed of light in vacuum
When using numeric constants, the shorter their names the better imho. Because they're inside a module that only contains them, I think they're mostly harmless. In case one has overlapping names, they can always rename them as:
use stdlib_constants, only: clight => c
Of course, it's important that their names are not confusing as @awvwgk https://github.com/awvwgk is suggesting. But here they're taken from Scipy, so, probably a good reference for most people coming from the Python world.
— Reply to this email directly, view it on GitHub https://github.com/fortran-lang/stdlib/pull/800#discussion_r1608552969, or unsubscribe https://github.com/notifications/unsubscribe-auth/AD5RO7DZ36D3LZGQH6ER4JTZDNTSLAVCNFSM6AAAAABGRC7NM6VHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZDANRYHE4TIMRTGY . You are receiving this because you were mentioned.Message ID: @.***>
Do we have an agreement to proceed without any prefix on the constants as they are defined in Scipy? @jvdp1
Thank you @MilanSkocic What do you think @perazz @jalvesz @awvwgk ?
LGTM!! brilliant work @MilanSkocic
thank you @MilanSkocic for this PR. I will merge it.
@MilanSkocic Don't hesitate to advertise this new addition on Discourse and other channels.
Thank you @jvdp1 ! I'm glad the codata constants have been merged. For sure I'll advertise the addition. It was a pleasure to contribute to the Fortran-lang community.
The codata constants are implemented as derived types (#347). This way, the values, the uncertainties and the units are easily available. Only the latest release is implemented i.e. 2018. The 2022 CODATA adjustment are not available yet.
The constants, as provided by the NIST, are double precision reals and I though it was useless to provide to include any other precision.
Your comments and suggestions are welcome.