Loading...
Searching...
No Matches
MPIPot.cpp
Go to the documentation of this file.
1/*
2** This file is part of eOn.
3**
4** SPDX-License-Identifier: BSD-3-Clause
5**
6** Copyright (c) 2010--present, eOn Development Team
7** All rights reserved.
8**
9** Repo:
10** https://github.com/TheochemUI/eOn
11*/
12
14#include "eon/Parameters.h"
15
16#include <array>
17#include <chrono>
18#include <cstdint>
19#include <filesystem>
20#include <mpi.h>
21#include <stdexcept>
22#include <string>
23#include <thread>
24
25namespace {
26
27void mpi_check(int rc, const char *what) {
28 if (rc != MPI_SUCCESS) {
29 throw std::runtime_error(std::string(what) + " failed");
30 }
31}
32
33} // namespace
34
36 : eonc::Potential(p) {
37 potentialRank = p.potential_options().MPIPotentialRank;
38 poll_period = p.potential_options().MPIPollPeriod;
39}
40
42
44
45void MPIPot::force(long N, const double *R, const int *atomicNrs, double *F,
46 double *U, double *variance, const double *box) {
47 if (variance != nullptr) {
48 *variance = 0.0;
49 }
50 // The peer receives the working directory as 1024 MPI_INT character
51 // codes, NUL terminated; the buffer element type must match MPI_INT.
52 std::array<int, 1024> icwd{};
53 const std::string cwd = std::filesystem::current_path().string();
54 if (cwd.size() >= icwd.size()) {
55 throw std::runtime_error(
56 "working directory path exceeds the MPI potential buffer");
57 }
58 for (std::size_t i = 0; i < cwd.size(); ++i) {
59 icwd[i] = static_cast<int>(static_cast<unsigned char>(cwd[i]));
60 }
61 int pbc = 1;
62 int failed = 0;
63 const int intn = static_cast<int>(N);
64 mpi_check(MPI_Send(&intn, 1, MPI_INT, potentialRank, 0, MPI_COMM_WORLD),
65 "MPI_Send atom count");
66 mpi_check(
67 MPI_Send(atomicNrs, intn, MPI_INT, potentialRank, 0, MPI_COMM_WORLD),
68 "MPI_Send atomic numbers");
69 mpi_check(MPI_Send(R, 3 * intn, MPI_DOUBLE, potentialRank, 0, MPI_COMM_WORLD),
70 "MPI_Send positions");
71 mpi_check(MPI_Send(box, 9, MPI_DOUBLE, potentialRank, 0, MPI_COMM_WORLD),
72 "MPI_Send cell");
73 mpi_check(MPI_Send(&pbc, 1, MPI_INT, potentialRank, 0, MPI_COMM_WORLD),
74 "MPI_Send pbc");
75 mpi_check(MPI_Send(icwd.data(), static_cast<int>(icwd.size()), MPI_INT,
76 potentialRank, 0, MPI_COMM_WORLD),
77 "MPI_Send working directory");
78
79 if (poll_period > 0.0) {
80 int eon_flag = 0;
81 // poll_period is in seconds (mpi_poll_period, default 0.25).
82 const auto usec = static_cast<std::uint64_t>(poll_period * 1000000.0);
83 mpi_check(MPI_Iprobe(potentialRank, 0, MPI_COMM_WORLD, &eon_flag,
84 MPI_STATUS_IGNORE),
85 "MPI_Iprobe");
86 while (!eon_flag) {
87 if (usec > 0) {
88 std::this_thread::sleep_for(std::chrono::microseconds(usec));
89 }
90 mpi_check(MPI_Iprobe(potentialRank, 0, MPI_COMM_WORLD, &eon_flag,
91 MPI_STATUS_IGNORE),
92 "MPI_Iprobe");
93 }
94 }
95
96 mpi_check(MPI_Recv(&failed, 1, MPI_INT, potentialRank, 0, MPI_COMM_WORLD,
97 MPI_STATUS_IGNORE),
98 "MPI_Recv status");
99 if (failed == 1) {
100 throw std::runtime_error("MPI potential reported a failed evaluation");
101 }
102
103 mpi_check(MPI_Recv(U, 1, MPI_DOUBLE, potentialRank, 0, MPI_COMM_WORLD,
104 MPI_STATUS_IGNORE),
105 "MPI_Recv energy");
106 mpi_check(MPI_Recv(F, 3 * intn, MPI_DOUBLE, potentialRank, 0, MPI_COMM_WORLD,
107 MPI_STATUS_IGNORE),
108 "MPI_Recv forces");
109}
void cleanMemory()
Definition MPIPot.cpp:41
void force(long N, const double *R, const int *atomicNrs, double *F, double *U, double *variance, const double *box) override
Definition MPIPot.cpp:45
MPIPot(const eonc::Parameters &p)
Definition MPIPot.cpp:35
double poll_period
Definition MPIPot.h:32
int potentialRank
Definition MPIPot.h:31
~MPIPot()
Definition MPIPot.cpp:43
const potential_options_t & potential_options() const
Potential(PotType a_ptype)
Production default: construction-scope registry, else PotRegistry::get().
RAII resource manager for the ARTn C library with global synchronization.