Skip to content

Commit c2c2019

Browse files
committed
Add runtime validation for ELPA complex BLOCK2 kernels
1 parent b1141ba commit c2c2019

4 files changed

Lines changed: 444 additions & 2 deletions

File tree

source/source_hsolver/module_genelpa/CMakeLists.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
add_library(genelpa OBJECT elpa_new.cpp elpa_new_real.cpp elpa_new_complex.cpp utils.cpp)
1+
add_library(genelpa OBJECT
2+
elpa_new.cpp
3+
elpa_new_real.cpp
4+
elpa_new_complex.cpp
5+
elpa_runtime_check.cpp
6+
utils.cpp
7+
)
28

39
if(ENABLE_COVERAGE)
410
add_coverage(genelpa)

source/source_hsolver/module_genelpa/elpa_new.cpp

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
#include "elpa_new.h"
22

3+
#include "elpa_runtime_check.h"
4+
35
#include "elpa_solver.h"
46
extern "C"
57
{
68
#include "Cblacs.h"
79
}
810
#include "utils.h"
11+
#include "source_base/tool_quit.h"
912
#include <cfloat>
1013
#include <complex>
1114
#include <cstring>
1215
#include <fstream>
16+
#include <iomanip>
1317
#include <iostream>
1418
#include <map>
1519
#include <mpi.h>
@@ -208,11 +212,71 @@ void ELPA_Solver::setLoglevel(int loglevel)
208212
void ELPA_Solver::setKernel(bool isReal, int kernel)
209213
{
210214
this->kernel_id = kernel;
211-
int error;
215+
int error = ELPA_OK;
212216
if (isReal)
217+
{
213218
elpa_set(NEW_ELPA_HANDLE_POOL[handle_id], "real_kernel", kernel, &error);
219+
}
214220
else
221+
{
215222
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+
}
216280
}
217281

218282
void ELPA_Solver::setQR(int useQR)

0 commit comments

Comments
 (0)