135 quill::BackendOptions backend_options;
137 backend_options.sleep_duration = std::chrono::microseconds{10};
139 backend_options.transit_event_buffer_initial_capacity = 2048;
141 backend_options.log_timestamp_ordering_grace_period =
142 std::chrono::microseconds{0};
144 backend_options.sink_min_flush_interval = std::chrono::milliseconds{100};
146 backend_options.check_printable_char = {};
147 quill::Backend::start(backend_options);
149 quill::Frontend::create_or_get_sink<quill::ConsoleSink>(
"console");
150 auto file_sink = quill::Frontend::create_or_get_sink<quill::FileSink>(
153 quill::FileSinkConfig cfg;
154 cfg.set_open_mode(
'w');
157 quill::FileEventNotifier{});
158 auto *logger = quill::Frontend::create_or_get_logger(
159 "combi", {std::move(console_sink), std::move(file_sink)},
160 quill::PatternFormatterOptions{
"%(message)"},
161 quill::ClockSourceType::System);
162 logger->set_log_level(quill::LogLevel::TraceL3);
165 quill::Frontend::create_or_get_sink<quill::ConsoleSink>(
"trace_console");
166 auto trace_fsink = quill::Frontend::create_or_get_sink<quill::FileSink>(
167 "client_traceback.log",
169 quill::FileSinkConfig cfg;
170 cfg.set_open_mode(
'w');
173 quill::FileEventNotifier{});
174 quill::Frontend::create_or_get_logger(
175 "_traceback", {std::move(trace_csink), std::move(trace_fsink)},
176 quill::PatternFormatterOptions{
177 " [%(log_level)] [%(source_location)] [%(caller_function)] \n "
178 "%(message)\n[end %(log_level)]"},
179 quill::ClockSourceType::System);
183#if defined WITH_ASE_ORCA || EMBED_PYTHON || WITH_ASE_NWCHEM
188 bool client_standalone =
false;
189 if (getenv(
"EON_CLIENT_STANDALONE") !=
nullptr) {
190 client_standalone =
true;
192 int number_of_clients;
193 if (!client_standalone) {
194 if (getenv(
"EON_SERVER_PATH") ==
nullptr) {
195 QUILL_LOG_ERROR(logger,
"error: must set the env var EON_SERVER_PATH");
199 if (getenv(
"EON_NUMBER_OF_CLIENTS") ==
nullptr) {
200 QUILL_LOG_ERROR(logger,
201 "error: must set the env var EON_NUMBER_OF_CLIENTS");
205 number_of_clients = atoi(getenv(
"EON_NUMBER_OF_CLIENTS"));
207 number_of_clients = 1;
210 int eon_mpi_inited = 0;
211 MPI_Initialized(&eon_mpi_inited);
212 if (!eon_mpi_inited) {
213 int eon_mpi_provided = 0;
214 MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &eon_mpi_provided);
218 std::string config_file =
"config.ini";
219 if (client_standalone) {
221 config_file =
"config_0.ini";
223 QUILL_LOG_INFO(logger,
"Loading parameter file {}", config_file);
224 error = parameters.load(config_file);
226 QUILL_LOG_INFO(logger,
"Loading parameter file {}",
227 parameters.main_options.iniFilename);
228 error = parameters.load(parameters.main_options.iniFilename);
231 QUILL_LOG_ERROR(logger,
"problem loading parameter file");
233 MPI_Abort(MPI_COMM_WORLD, 1);
237 MPI_Barrier(MPI_COMM_WORLD);
240 MPI_Comm_rank(MPI_COMM_WORLD, &irank);
242 MPI_Comm_size(MPI_COMM_WORLD, &isize);
244 std::vector<int> process_types(isize);
249 MPI_Allgather(&process_type, 1, MPI_INT, &process_types[0], 1, MPI_INT,
252 int i, servers = 0, clients = 0, potentials = 0;
253 int server_rank = -1;
254 int my_client_number = -1;
255 std::vector<int> client_ranks;
256 for (i = 0; i < isize; i++) {
257 switch (process_types[i]) {
263 my_client_number = clients;
266 client_ranks.push_back(i);
274 if (clients < number_of_clients) {
275 QUILL_LOG_ERROR(logger,
276 "didn't launch as many mpi client ranks as specified in "
277 "EON_NUMBER_OF_CLIENTS");
279 MPI_Abort(MPI_COMM_WORLD, 1);
281 clients = number_of_clients;
283 if (parameters.potential_options.potential == PotType::MPI) {
284 std::vector<int> potential_ranks(potentials);
286 for (i = 0, j = 0; i < isize; i++) {
287 if (process_types[i] == 2) {
288 potential_ranks[j] = i;
292 int potential_group_size = potentials / clients;
294 for (i = 0; i < clients; i++) {
295 MPI_Group orig_group, new_group;
296 MPI_Comm_group(MPI_COMM_WORLD, &orig_group);
297 int offset = i * potential_group_size;
298 MPI_Group_incl(orig_group, potential_group_size, &potential_ranks[offset],
301 MPI_Comm_create(MPI_COMM_WORLD, new_group, &pot_comm);
304 if (my_client_number < number_of_clients) {
305 parameters.potential_options.MPIPotentialRank =
306 potential_ranks[my_client_number * potential_group_size];
311 if (parameters.potential_options.potential == PotType::LAMMPS) {
312 for (i = 0; i < static_cast<int>(client_ranks.size()); i++) {
313 MPI_Group world_group, new_group;
314 MPI_Comm_group(MPI_COMM_WORLD, &world_group);
315 int r = client_ranks[i];
316 MPI_Group_incl(world_group, 1, &r, &new_group);
318 MPI_Comm_create(MPI_COMM_WORLD, new_group, &new_comm);
319 if (new_comm != MPI_COMM_NULL) {
320 parameters.potential_options.MPIClientComm = new_comm;
322 QUILL_LOG_INFO(logger,
"creating group with ranks: {}", r);
326 if (!client_standalone) {
327 server_rank = client_ranks[number_of_clients];
328 if (my_client_number == number_of_clients) {
329 std::ostringstream oss;
330 oss << client_ranks.at(0);
331 for (i = 1; i < number_of_clients; i++) {
332 oss <<
":" << client_ranks.at(i);
334 setenv(
"EON_CLIENT_RANKS", oss.str().c_str(), 1);
337 static_cast<wchar_t **
>(malloc(
sizeof(
wchar_t *) * 2));
338 py_argv[0] = Py_DecodeLocale(argv[0],
nullptr);
339 char *program = getenv(
"EON_SERVER_PATH");
340 py_argv[1] = Py_DecodeLocale(program,
nullptr);
341 QUILL_LOG_INFO(logger,
"rank: {} becoming {}", irank, program);
348 }
else if (my_client_number > number_of_clients) {
364 auto start_time = std::chrono::steady_clock::now();
369 char logfilename[1024];
370 snprintf(logfilename, 1024,
"eonclient_%i.log", my_client_number);
372 auto orig_path = std::filesystem::current_path();
374 std::filesystem::current_path(orig_path);
375 std::string path(1024,
'\0');
377 if (!client_standalone) {
379 logger,
"client: rank {} is ready, posting send to server rank: {}!",
385 MPI_Isend(&ready, 1, MPI_INT, server_rank, 1, MPI_COMM_WORLD, &eon_rq);
386 MPI_Request_free(&eon_rq);
390 MPI_Recv(&path[0], 1024, MPI_CHAR, server_rank, 0, MPI_COMM_WORLD,
392 if (path.starts_with(
"STOPCAR")) {
393 QUILL_LOG_INFO(logger,
"rank {} got STOPCAR", irank);
397 QUILL_LOG_INFO(logger,
"client: rank: {} chdir to {}", irank, path);
400 std::filesystem::current_path(path.c_str());
401 }
catch (
const std::filesystem::filesystem_error &e) {
402 QUILL_LOG_ERROR(logger,
"error: chdir: {}", e.what());
410 bool bundlingEnabled =
false;
412 if (bundleSize == 0) {
414 }
else if (bundleSize == -1) {
417 bundlingEnabled =
false;
420 std::vector<std::string> bundledFilenames;
421 for (
int i = 0; i < bundleSize; i++) {
423 QUILL_LOG_INFO(logger,
"Beginning Job {} of {}", i + 1, bundleSize);
424 std::vector<std::string> unbundledFilenames;
425 if (bundlingEnabled) {
431 std::string config_file =
433 QUILL_LOG_INFO(logger,
"Loading parameter file {}", config_file);
434 error = parameters.load(config_file);
437 QUILL_LOG_ERROR(logger,
"problem loading parameter file, stopping");
447 if (job ==
nullptr) {
448 QUILL_LOG_ERROR(logger,
"error: Unknown job: {}",
449 std::string{magic_enum::enum_name<JobType>(
450 parameters.main_options.job)});
455 std::vector<std::string> filenames;
457 filenames = job->run();
459 QUILL_LOG_CRITICAL(logger,
"[ERROR] job exited on error {}", e);
461 }
catch (
const std::exception &e) {
462 QUILL_LOG_CRITICAL(logger,
"[ERROR] unhandled exception: {}", e.what());
464 std::cerr <<
"[ERROR] unhandled exception: " << e.what() <<
"\n";
470 filenames.push_back(std::string(
"_potcalls.json"));
471 filenames.push_back(std::string(
"client_quill.log"));
472 filenames.push_back(std::string(
"client_traceback.log"));
475 std::ofstream manifest(
"return_files.dat");
477 for (
const auto &fn : filenames) {
478 manifest << fn <<
"\n";
481 filenames.push_back(std::string(
"return_files.dat"));
485 auto end_time = std::chrono::steady_clock::now();
486 std::chrono::duration<double> elapsed = end_time - start_time;
488 double utime = 0, stime = 0, rtime = 0;
491 QUILL_LOG_INFO(logger,
"Timing Information:");
492 QUILL_LOG_INFO(logger,
" Real time: {:.3f} seconds", elapsed.count());
493 QUILL_LOG_INFO(logger,
" User time: {:.3f} seconds", utime);
494 QUILL_LOG_INFO(logger,
" System time: {:.3f} seconds", stime);
498 std::ofstream result_file(
"results.dat", std::ios::app);
499 if (result_file.is_open()) {
500 result_file << std::format(
"{:.12e} time_seconds\n", elapsed.count());
502 result_file << std::format(
"{:.12e} user_time\n", utime);
503 result_file << std::format(
"{:.12e} system_time\n", stime);
506 QUILL_LOG_ERROR(logger,
"Failed to write timing to results.dat");
509 if (bundlingEnabled) {
513 bundledFilenames = filenames;
518 if (client_standalone) {
523 MPI_Isend(&path[0], 1024, MPI_CHAR, server_rank, 0, MPI_COMM_WORLD,
525 MPI_Request_free(&eon_rq);
534 print_memory_usage();
545 quill::Backend::stop();