80 (1024.0 * 1024.0 * 1024.0));
86 log::info(
"GPU memory allocate/deallocate: OK");
90 const std::string& blas_library_name) {
95 std::vector<Complex> test_vector = {
Complex(1.0, 0.0),
Complex(0.0, 1.0)};
97 double error = std::abs(dot_result.real() - 2.0) + std::abs(dot_result.imag());
98 if (error > 1.0e-14) {
99 throw std::runtime_error(
"GPU BLAS dot product validation failed");
101 if (blas_library_name.empty()) {
104 log::info(
"GPU BLAS ({}) validation: OK", blas_library_name);
109 const std::string& eigensolver_library_name) {
112 std::vector<Real> eigenvalues(2);
114 double eigen_error = std::abs(eigenvalues[0] - 1.0) + std::abs(eigenvalues[1] - 3.0);
115 if (eigen_error > 1.0e-12) {
116 throw std::runtime_error(
"GPU eigensolver validation failed");
118 if (eigensolver_library_name.empty()) {
119 log::info(
"GPU eigensolver validation: OK");
121 log::info(
"GPU eigensolver ({}) validation: OK", eigensolver_library_name);
141 if (options.print_version) {
157 if (launcher_tasks.count > 1) {
163 const bool packing_independent_runs = std::getenv(
"Q3_ALLOW_MULTI_TASK_GPU") !=
nullptr;
164 constexpr const char* message =
165 "{} was launched as {} tasks ({}={}), and it has no multi-process mode: each task "
166 "would set up the whole problem on its own device and solve all of it, giving {} "
167 "identical answers for {}x the allocation. Run it as one task, or use q3_mpi to "
168 "spread k-points across ranks on CPU, or q3_mpi_gpu_cuda to spend one device "
169 "per rank on a single calculation. Set "
170 "Q3_ALLOW_MULTI_TASK_GPU=1 to proceed anyway, which is right only when the tasks "
171 "are packing independent calculations into one step.";
172 if (!packing_independent_runs) {
175 launcher_tasks.count,
176 launcher_tasks.variable,
177 launcher_tasks.count,
178 launcher_tasks.count,
179 launcher_tasks.count);
184 launcher_tasks.count,
185 launcher_tasks.variable,
186 launcher_tasks.count,
187 launcher_tasks.count,
188 launcher_tasks.count);
191 if (!options.log_level.empty()) {
195 bool use_mixed_precision =
false;
196 if (options.precision ==
"mixed") {
197 use_mixed_precision =
true;
198 }
else if (!options.precision.empty() && options.precision !=
"double") {
199 log::error(
"Unknown precision: {}. Use 'double' or 'mixed'.", options.precision);
208 if (!input.hubbard.empty()) {
209 log::error(
"DFT+U (hubbard) is not yet supported on GPU. Run on CPU instead.");
218 auto gpu_blas = descriptor.
create_blas(device_backend);
228 std::unique_ptr<gpu::GPUFFTGrid> gpu_fft_grid;
245 auto execution_policy = std::make_unique<execution::PlanewaveSerialExecutionPolicy>();
248 iterator->set_owned_execution_policy(std::move(execution_policy));
250 auto gpu_davidson = std::make_unique<PlanewaveDavidsonDiagonalizer>(
256 if (use_mixed_precision) {
257 gpu_davidson->set_use_mixed_precision(
true);
259 iterator->set_diagonalizer(std::move(gpu_davidson));
264 log::info(
" Calculation type: {}", input.calculation);
265 auto flavor =
create_flavor(input.calculation, std::move(iterator_factory));
266 generated::Results results = flavor->run(input);
267 write_results_json(results, input.output_directory +
"/" + input.prefix +
"_results.json");
270 }
catch (
const std::exception& exception) {
276 q3::log::info(
" Total FFT calls: {}", profiling.fft_call_count.load());
278 profiling.davidson_iteration_count.load());
280 profiling.hamiltonian_application_count.load());
281 profiling.print_memory_summary();
282 profiling.davidson_timing.print_summary();
static const execution::SerialExecutionPolicy default_serial_execution_policy
virtual Complex dot_product(int number_of_elements, const Complex *vector_x, const Complex *vector_y) const =0
virtual bool supports_double_precision() const =0
virtual size_t total_memory_bytes() const =0
virtual void deallocate(void *pointer)=0
virtual void * allocate_unified(size_t size_bytes)=0
virtual std::string device_name() const =0
virtual void hermitian_eigenvalue_solve(int matrix_dimension, Complex *matrix_data, int leading_dimension, Real *eigenvalues)=0
void register_all()
No add-on is compiled in, so there is nothing to register.
void validate_gpu_eigensolver(execution::gpu::lapack::GPUEigensolver &gpu_eigensolver, const std::string &eigensolver_library_name)
int run_gpu_entry_point(int argc, char *argv[], const GPUEntryPointDescriptor &descriptor)
void validate_gpu_device_backend(execution::gpu::device::GPUDeviceBackend &device_backend)
void validate_gpu_blas(execution::gpu::blas::GPUBLAS &gpu_blas, const std::string &blas_library_name)
Options parse_options(int argc, char *argv[], const std::string &binary_name)
void print_version(const std::string &binary_name)
LauncherTasks detect_launcher_tasks()
The same, against the real environment.
InputData read_input(Options &options, const std::string &binary_name)
void print_timestamped_banner(const std::string &label_prefix)
std::shared_ptr< GPUDeviceBackend > create_gpu_device_backend()
void init(const std::string &log_file="")
void warn(spdlog::format_string_t< Args... > fmt, Args &&... args)
void error(spdlog::format_string_t< Args... > fmt, Args &&... args)
void info(spdlog::format_string_t< Args... > fmt, Args &&... args)
void set_level(const std::string &level)
Set log level: "trace", "debug", "info", "warn", "error", "off".
void write_results_json(const generated::Results &results, const std::string &output_path)
Write the results to output_path as results.json.
std::unique_ptr< Flavor > create_flavor(const std::string &calculation_type, IteratorFactory iterator_factory={})
std::function< std::unique_ptr< PlanewaveKohnShamSCFIterator >(const InputData &)> IteratorFactory
std::complex< double > Complex
void write_companion_outputs(const InputData &input, const generated::Results &results)
Write the companion outputs of the format input was read from, if it has any.
std::unique_ptr< PlanewaveKohnShamSCFIterator > create_kohn_sham_iterator(const InputData &input, const execution::PlanewaveExecutionPolicy &execution_policy)
static ProfilingCounters & instance()
std::string backend_label
Banner label, e.g. "CUDA GPU" → "BEGIN (CUDA GPU): <timestamp>".
std::function< std::unique_ptr< execution::gpu::blas::GPUBLAS >(DeviceBackendPointer)> create_blas
std::function< std::unique_ptr< execution::gpu::lapack::GPUEigensolver >(DeviceBackendPointer)> create_eigensolver
std::string binary_name
Binary name for the usage line, e.g. "q3_gpu_cuda".
std::shared_ptr< execution::gpu::device::GPUDeviceBackend > DeviceBackendPointer
std::string eigensolver_library_name
Vendor eigensolver name for the validation log line, e.g. "cuSOLVER". Optional.
std::string blas_library_name
Vendor BLAS name for the validation log line, e.g. "cuBLAS". Optional.
std::function< std::unique_ptr< gpu::GPUFFTGrid >(DeviceBackendPointer)> create_fft_grid
std::string mixed_precision_description
Human-readable description of the mixed-precision mode, e.g. "mixed (FP32 FFT via cuFFT)".