116 double *F,
double *U,
double *variance,
119 forceOnce(N, R, atomicNrs, F, U, variance, box);
121 }
catch (
const std::runtime_error &) {
124 forceOnce(N, R, atomicNrs, F, U, variance, box);
128 double *F,
double *U,
double *variance,
131 std::vector<std::string> symbols;
133 for (
long i = 0; i < N; ++i) {
134 const int z = atomicNrs[i];
135 symbols.emplace_back(
136 z > 0 ? readcon::z_to_symbol(
static_cast<uint64_t
>(z)) :
"X");
148 std::array<char, MSG_LEN + 1> status_buffer{};
154 if (std::string(status_buffer.data()) !=
"READY") {
155 throw std::runtime_error(
156 "Handshake failed: NWChem client not READY. It sent: " +
157 std::string(status_buffer.data()));
163 std::array<char, MSG_LEN + 1> status_buffer{};
167 if (std::string(status_buffer.data()) ==
"NEEDINIT") {
170 std::array<int32_t, 2> init_payload{{0, 1}};
172 send_exact(init_payload.data(), init_payload.size() *
sizeof(int32_t));
179 if (std::string(status_buffer.data()) !=
"READY") {
180 throw std::runtime_error(
"NWChem server not ready for new positions!");
184 std::vector<double> pos_bohr(N * 3);
185 for (
size_t i = 0; i < pos_bohr.size(); ++i) {
192 std::array<double, 9> invcell_T{{1, 0, 0, 0, 1, 0, 0, 0, 1}};
193 std::array<double, 9> cell_T{{1, 0, 0, 0, 1, 0, 0, 0, 1}};
196 int32_t nat =
static_cast<int32_t
>(N);
197 send_exact(cell_T.data(), cell_T.size() *
sizeof(
double));
198 send_exact(invcell_T.data(), invcell_T.size() *
sizeof(
double));
200 send_exact(pos_bohr.data(), pos_bohr.size() *
sizeof(
double));
206 if (std::string(status_buffer.data()) ==
"HAVEDATA") {
210 std::this_thread::sleep_for(std::chrono::milliseconds(10));
216 if (std::string(status_buffer.data()) !=
"FORCEREADY") {
217 throw std::runtime_error(
"Expected FORCEREADY, got " +
218 std::string(status_buffer.data()));
224 std::vector<double> forces_ha_bohr(N * 3);
225 std::array<double, 9> virial_ha{};
231 throw std::runtime_error(
"Atom count mismatch from NWChem");
232 recv_exact(forces_ha_bohr.data(), forces_ha_bohr.size() *
sizeof(
double));
233 recv_exact(virial_ha.data(), virial_ha.size() *
sizeof(
double));
237 const double volume =
238 box ==
nullptr ? 0.0 : std::abs(Matrix3d::Map(box).determinant());
243 for (
int row = 0; row < 3; ++row) {
244 for (
int col = 0; col < 3; ++col) {
246 0.5 * (virial_ha[
static_cast<size_t>(row * 3 + col)] +
247 virial_ha[
static_cast<size_t>(col * 3 + row)]);
248 stress_(row, col) = vij * scale;
254 std::vector<char> extra_buf(extra_len);
260 for (
int i = 0; i < N * 3; ++i) {
263 if (variance !=
nullptr) {
279 throw std::runtime_error(std::format(
"{}: {}", what, std::strerror(err)));
286 listen_fd = socket(domain, SOCK_STREAM, 0);
288 throw std::runtime_error(
289 std::format(
"Failed to create socket: {}", std::strerror(errno)));
294 sockaddr_un sock_addr{};
295 sock_addr.sun_family = AF_UNIX;
297 sizeof(sock_addr.sun_path) - 1);
299 socklen_t addr_len =
static_cast<socklen_t
>(
300 sizeof(sock_addr.sun_family) + std::strlen(sock_addr.sun_path));
301 if (::bind(
listen_fd,
reinterpret_cast<sockaddr *
>(&sock_addr), addr_len) <
305 socket_fail(fd,
"Failed to bind UNIX socket");
309 if (setsockopt(
listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt,
sizeof(opt)) <
313 socket_fail(fd,
"Failed to set SO_REUSEADDR");
315 sockaddr_in sock_addr{};
316 sock_addr.sin_family = AF_INET;
320 if (sock_addr.sin_addr.s_addr == INADDR_NONE) {
323 throw std::runtime_error(
324 "Failed to parse the TCP host as an IPv4 address");
326 sock_addr.sin_port = htons(
static_cast<uint16_t
>(
port));
328 if (::bind(
listen_fd,
reinterpret_cast<sockaddr *
>(&sock_addr),
329 sizeof(sock_addr)) < 0) {
332 socket_fail(fd,
"Failed to bind TCP socket");
339 socket_fail(fd,
"Socket listen() failed");
361 std::array<char, MSG_LEN> buffer{};
362 const std::size_t n = std::min(std::strlen(msg), buffer.size());
363 std::copy_n(msg, n, buffer.begin());
void force(long N, const double *R, const int *atomicNrs, double *F, double *U, double *variance, const double *box) override
The method called to compute forces and energy.
void forceOnce(long N, const double *R, const int *atomicNrs, double *F, double *U, double *variance, const double *box)