23#undef HWY_TARGET_INCLUDE
24#define HWY_TARGET_INCLUDE "client/ForceNorm.cpp"
25#include <hwy/foreach_target.h>
26#include <hwy/highway.h>
28HWY_BEFORE_NAMESPACE();
30namespace HWY_NAMESPACE {
32namespace hn = hwy::HWY_NAMESPACE;
34double MaxFreeAtomForceNorm(
const double *HWY_RESTRICT forces,
35 const double *HWY_RESTRICT fixed,
long nAtoms) {
36 if (forces ==
nullptr || nAtoms <= 0) {
39 const hn::ScalableTag<double> d;
40 const size_t lanes = hn::Lanes(d);
41 const size_t n =
static_cast<size_t>(nAtoms);
42 const auto half = hn::Set(d, 0.5);
43 auto vmax = hn::Zero(d);
46 for (; i + lanes <= n; i += lanes) {
50 hn::LoadInterleaved3(d, forces + 3 * i, x, y, z);
54 hn::Sqrt(hn::Add(hn::Add(hn::Mul(x, x), hn::Mul(y, y)), hn::Mul(z, z)));
55 if (fixed !=
nullptr) {
56 auto fx = hn::Zero(d);
57 auto fy = hn::Zero(d);
58 auto fz = hn::Zero(d);
59 hn::LoadInterleaved3(d, fixed + 3 * i, fx, fy, fz);
60 const auto allFixed = hn::And(
61 hn::Gt(fx, half), hn::And(hn::Gt(fy, half), hn::Gt(fz, half)));
62 const auto free = hn::IfThenElseZero(hn::Not(allFixed), nrm);
65 if (!hn::AllFalse(d, hn::IsNaN(free))) {
66 return std::numeric_limits<double>::quiet_NaN();
68 vmax = hn::Max(vmax, free);
70 if (!hn::AllFalse(d, hn::IsNaN(nrm))) {
71 return std::numeric_limits<double>::quiet_NaN();
73 vmax = hn::Max(vmax, nrm);
77 const double tail = detail::maxFreeAtomForceNormScalar(
78 forces, fixed,
static_cast<long>(i), nAtoms);
79 if (std::isnan(tail)) {
82 return std::max(hn::ReduceMax(d, vmax), tail);
92HWY_EXPORT(MaxFreeAtomForceNorm);
96 return HWY_DYNAMIC_DISPATCH(MaxFreeAtomForceNorm)(forces, fixed, nAtoms);
double maxFreeAtomForceNormScalar(const double *forces, const double *fixed, long begin, long nAtoms)
Scalar max of per-atom Euclidean norms on [begin, nAtoms).
RAII resource manager for the ARTn C library with global synchronization.
double maxFreeAtomForceNorm(const double *forces, const double *fixed, long nAtoms)
Max Euclidean norm over N x 3 row-major force rows.