|
1 | 1 | #include "elpa_new.h" |
2 | 2 |
|
| 3 | +#include "elpa_runtime_check.h" |
| 4 | + |
3 | 5 | #include "elpa_solver.h" |
4 | 6 | extern "C" |
5 | 7 | { |
6 | 8 | #include "Cblacs.h" |
7 | 9 | } |
8 | 10 | #include "utils.h" |
| 11 | +#include "source_base/tool_quit.h" |
9 | 12 | #include <cfloat> |
10 | 13 | #include <complex> |
11 | 14 | #include <cstring> |
12 | 15 | #include <fstream> |
| 16 | +#include <iomanip> |
13 | 17 | #include <iostream> |
14 | 18 | #include <map> |
15 | 19 | #include <mpi.h> |
@@ -208,11 +212,71 @@ void ELPA_Solver::setLoglevel(int loglevel) |
208 | 212 | void ELPA_Solver::setKernel(bool isReal, int kernel) |
209 | 213 | { |
210 | 214 | this->kernel_id = kernel; |
211 | | - int error; |
| 215 | + int error = ELPA_OK; |
212 | 216 | if (isReal) |
| 217 | + { |
213 | 218 | elpa_set(NEW_ELPA_HANDLE_POOL[handle_id], "real_kernel", kernel, &error); |
| 219 | + } |
214 | 220 | else |
| 221 | + { |
215 | 222 | elpa_set(NEW_ELPA_HANDLE_POOL[handle_id], "complex_kernel", kernel, &error); |
| 223 | + } |
| 224 | + |
| 225 | + int local_set_failed = error == ELPA_OK ? 0 : 1; |
| 226 | + int any_set_failed = 0; |
| 227 | + MPI_Allreduce(&local_set_failed, &any_set_failed, 1, MPI_INT, MPI_MAX, comm); |
| 228 | + if (any_set_failed != 0) |
| 229 | + { |
| 230 | + ModuleBase::WARNING_QUIT("ELPA_Solver::setKernel", |
| 231 | + "Failed to select the requested ELPA kernel on at least one MPI rank."); |
| 232 | + } |
| 233 | + |
| 234 | + if (isReal) |
| 235 | + { |
| 236 | + return; |
| 237 | + } |
| 238 | + |
| 239 | + int local_check_required = needs_elpa_complex_block2_runtime_check(kernel) ? 1 : 0; |
| 240 | + int any_check_required = 0; |
| 241 | + MPI_Allreduce(&local_check_required, &any_check_required, 1, MPI_INT, MPI_MAX, comm); |
| 242 | + if (any_check_required == 0) |
| 243 | + { |
| 244 | + return; |
| 245 | + } |
| 246 | + |
| 247 | + ElpaRuntimeCheckResult result{true, 0.0, 0.0}; |
| 248 | + if (local_check_required != 0) |
| 249 | + { |
| 250 | + static std::map<int, ElpaRuntimeCheckResult> checked_kernels; |
| 251 | + std::map<int, ElpaRuntimeCheckResult>::iterator it = checked_kernels.find(kernel); |
| 252 | + if (it == checked_kernels.end()) |
| 253 | + { |
| 254 | + const ElpaRuntimeCheckResult checked_result = check_elpa_complex_block2_kernel(kernel); |
| 255 | + it = checked_kernels.emplace(kernel, checked_result).first; |
| 256 | + } |
| 257 | + result = it->second; |
| 258 | + } |
| 259 | + |
| 260 | + int local_failed = result.passed ? 0 : 1; |
| 261 | + int any_failed = 0; |
| 262 | + MPI_Allreduce(&local_failed, &any_failed, 1, MPI_INT, MPI_MAX, comm); |
| 263 | + |
| 264 | + if (any_failed != 0) |
| 265 | + { |
| 266 | + double max_residual = result.max_residual; |
| 267 | + double max_orthogonality = result.orthogonality; |
| 268 | + MPI_Allreduce(MPI_IN_PLACE, &max_residual, 1, MPI_DOUBLE, MPI_MAX, comm); |
| 269 | + MPI_Allreduce(MPI_IN_PLACE, &max_orthogonality, 1, MPI_DOUBLE, MPI_MAX, comm); |
| 270 | + |
| 271 | + std::ostringstream message; |
| 272 | + message << "The selected ELPA complex 2-stage BLOCK2 kernel failed a runtime correctness check. " |
| 273 | + << "The linked ELPA library may return incorrect eigenvectors. " |
| 274 | + << "Maximum residual = " << std::scientific << std::setprecision(6) << max_residual |
| 275 | + << ", orthogonality error = " << max_orthogonality << ". " |
| 276 | + << "Please rebuild ELPA, select a BLOCK1 kernel, or use another eigensolver. " |
| 277 | + << "For ELPA built with GCC 15.2, -fno-tree-slp-vectorize is a known workaround."; |
| 278 | + ModuleBase::WARNING_QUIT("ELPA_Solver::setKernel", message.str()); |
| 279 | + } |
216 | 280 | } |
217 | 281 |
|
218 | 282 | void ELPA_Solver::setQR(int useQR) |
|
0 commit comments