-
Notifications
You must be signed in to change notification settings - Fork 471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generalize floating point type #3922
Conversation
Since this PR seems to be introducing a huge ABI-breaking change, would you guys consider adopting inline namespaces (for single vs. double precision) to avoid creating ABI-incompatibility headaches for mfem's users? See, for example: https://www.youtube.com/watch?v=rUESOjhvLw0 Also, is it the case that |
config/cmake/MFEMConfig.cmake.in
Outdated
@@ -63,6 +63,7 @@ set(MFEM_USE_ALGOIM @MFEM_USE_ALGOIM@) | |||
set(MFEM_USE_BENCHMARK @MFEM_USE_BENCHMARK@) | |||
set(MFEM_USE_PARELAG @MFEM_USE_PARELAG@) | |||
set(MFEM_USE_ENZYME @MFEM_USE_ENZYME@) | |||
set(MFEM_USE_FLOAT @MFEM_USE_FLOAT@) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This really means "MFEM_USE_SINGLE_PRECISION" right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably need to adjust this, but basically the idea in this branch is that we can replace all doubles with another type e.g. float
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it means to use float
as the floating point type, see general/globals.hpp
. We may also want to add options for long double
and maybe even half precision for the most adventurous users. The changes are mostly general, so that any floating point type could be used, but a few places requires specially defined constants (e.g. tolerances for Newton solvers), so we may need different flags for different precision levels. I'm sure there will be opinions about names for these flags.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That means the MFEM_USE_XXX
macros are not the right way to provide this option. It's more convenient to provide a build macro like MFEM_FP_TYPE=XXX
where the person who builds MFEM puts the type. This would save quite a bit of ifdefs in general/globals.hpp
.
This is an interesting suggestion, how do you suggest we use it exactly? |
We are essentially doing the same thing as hypre -- typedefing the type that was double before. I agree this is not ideal, but it is a restriction that we have no control over. I personally am not aware of applications that link with different builds of hypre, and I will expect the same to be true for MFEM. |
@samuelpmishLLNL If I understood this correctly, for every class in MFEM (e.g. named I'm not sure if this is necessary for every class, or if this namespace could be used for the entire file. Or why not just use a normal namespace (without inline) for every file? Or is there a better way that I'm missing? It may be sufficient to do this just for |
If I understand correctly, rather than having everything live in the mfem namespace namespace mfem {
class Vector { ... };
class Mesh { ... };
} you would have anything with a different ABI for single/double live in a separate inline namespace, like // in some header, maybe config.hpp
#if mfem_uses_single_precision
#define PRECISION float32
#else
#define PRECISION float64
#endif
///////////////
namespace mfem {
inline namespace PRECISION {
class Vector { ... };
class Mesh { ... };
}
} That way, the underlying symbols have different names and prevent a code that expects
I don't agree with the second statement: hypre and mfem are written in different languages, so they have different tools available to them. hypre is mostly a C library, so if hypre wants to support different floating point precisions the only choices I know of are:
If it is the case that hypre went with option 2, that seems like the wrong choice for a linear algebra library. By comparison, LAPACK doesn't force users to pick exactly one kind of floating point precision, why should hypre? In contrast, mfem is a C++ library, so it has way more options to choose from for managing different precisions (function overloads, namespaces, templates, ...). Choosing to use the C-language mechanisms is an option but not a requirement. Also, if you feel that hypre is forcing you to write code you believe hurts mfem's usability then let's talk with the hypre developers about it, and see if we can address the underlying cause.
If I'm understanding things correctly, the causality is backwards here: applications don't link against multiple builds of hypre because hypre's I would ask that you give mfem's users the benefit of the doubt when it comes to supporting mixed precision. There are a lot of interesting research opportunities in mixed precision, and it's especially relevant for GPUs since cheap consumer hardware has single-precision performance that rivals the even the fanciest flagship GPUs: NVIDIA RTX 4080 ($1000): 50 TFLOPS FP32
Inline namespaces don't have to be explicitly referenced by the user, so people could still write
I would bet that it's not sufficient to apply the inline namespaces to only |
Is there a way to disable the branch history check? It fails because too many files were committed. |
You can temporarily edit this: mfem/tests/scripts/branch-history Lines 63 to 64 in ecfab8f
However, just so we don't forget to revert it before merging, create a TODO checkbox for it in the first comment above. |
Re-merged in |
Fix warnings about RAND_MAX when using single precision. Introduce an inline function `real_t rand_real()` that returns a random number in the interval [0,1) using rand(). This function handles better the case of single precision where the expression `real_t(rand())/(real_t(RAND_MAX)+1)` can return 1.0f due to round-off when rand() returns a number close to RAND_MAX. Use `rand_real()` in a few places that before used code similar to `real_t(rand())/(real_t(RAND_MAX)+1)`.
Re-merged in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for all your hard work on this @dylan-copeland and @v-dobrev !
My build with MUMPS now fails. I have a question. Should -lsmumps or -ldmumps be before -lmumps_common -lpord? |
FindMUMPS.cmake needs update too. |
Oops, I forgot to update this part: Lines 323 to 327 in bcdf7cc
Try replacing the
similar to here: Line 212 in bcdf7cc
Another option will be to move the logic for "MFEM_PRECISION -> MFEM_USE_SINGLE, MFEM_USE_DOUBLE" from the top level
You are right. If using double precision, it should still work though. |
CI build and test is done in #4262 😉 |
See TODO items
The following are working, with exceptions listed below:
gslib
, serial and parallel (with hypre), float and double.pcuda
build on GPU, serial and parallel, float and double.The following are not working or not supported. Examples and miniapps that do not work in single precision abort with an error message.
rel_tol
is set.Error in LOBPCG: GEVP solver failure
.nan
apparently inPartialFractionExpansion
, where many numbers are multiplied.nan
inGetMaximumTimeStep()
.NNLSSolver
).nan
.conduitdatacollection.cpp
,fmsconvert.*
,gslib.*
,sidredatacollection.*
,fem/moonolith/*
.hiop.*
.double
have not yet been added.Most of the changes are simply
double
->real_t
, withreal_t
defined as eitherfloat
ordouble
ingeneral/globals.hpp
, depending on the build flagMFEM_USE_SINGLE
. Some noteworthy changes areMPI_DOUBLE
->MPITypeMap<real_t>::mpi_type
fmax
->std::max
, etc.QuadratureFunctions1D::GaussLobatto
in intrules.cpp.64F
->32F
,Dcsr
->Scsr
.atomicAdd
in general/backends.hpp, which now has different implementations.real_t
, one of the inconveniences that will persist after this PR is merged.CONTRIBUTING.md
states a policy of usingreal_t
instead ofdouble
when possible.Support for floating point types other than float and double is left for a future PR, which should involve many fewer lines of code.
In single-precision, the unit tests build but are not expected to run. A future PR should support single-precision unit tests.
PR Checklist
make style
.CHANGELOG
:CHANGELOG
to group with other related features?INSTALL
:make
orcmake
have a new target?.github
.appveyor.yml
.gitignore
:make distclean; git status
shows any files that were generated from the source by the project (not an IDE) but we don't want to track in the repository.examples/makefile
:SEQ_EXAMPLES
andPAR_EXAMPLES
variables.clean
target..gitignore
file.examples/CMakeLists.txt
:ALL_EXE_SRCS
variable.THIS_TEST_OPTIONS
is set correctly for the new example.doc/CodeDocumentation.dox
.examples/pumi
), list it indoc/CodeDocumentation.conf.in
src/examples.md
.src/examples.md
andsrc/img
.examples.md
, list the example under the appropriate categories, add new categories if necessary.features.md
.makefile
andmakefile
in corresponding miniapp directory..gitignore
file.CMakeLists.txt
file in theminiapps
directory, if the new miniapp is in a new directory.CMakeLists.txt
file in the new miniapp directory.doc/CodeDocumentation.dox
miniapps/nurbs
), add it toMINIAPP_SUBDIRS
in themakefile
.miniapps/nurbs
), list it indoc/CodeDocumentation.conf.in
src/meshing.md
andsrc/electromagnetics.md
files.src/examples.md
andsrc/img
.features.md
.mfem/web
repo.README
(rare).doc/CodeDocumentation.dox
(rare).make unittest
to make sure all unit tests pass.tests/scripts
.