OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
Accumulator.hpp
1/*
2 * Copyright (c) 2004-present, The University of Notre Dame. All rights
3 * reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
32 * research, please cite the following paper when you publish your work:
33 *
34 * [1] Drisko et al., J. Open Source Softw. 9, 7004 (2024).
35 *
36 * Good starting points for code and simulation methodology are:
37 *
38 * [2] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
39 * [3] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
40 * [4] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
41 * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
42 * [6] Kuang & Gezelter, Mol. Phys., 110, 691-701 (2012).
43 * [7] Lamichhane, Gezelter & Newman, J. Chem. Phys. 141, 134109 (2014).
44 * [8] Bhattarai, Newman & Gezelter, Phys. Rev. B 99, 094106 (2019).
45 * [9] Drisko & Gezelter, J. Chem. Theory Comput. 20, 4986-4997 (2024).
46 */
47
48#ifndef OPENMD_UTILS_ACCUMULATOR_HPP
49#define OPENMD_UTILS_ACCUMULATOR_HPP
50
51#include <cassert>
52#include <cmath>
53#include <cstddef>
54#include <limits>
55#include <type_traits>
56#include <vector>
57
58#include "math/SquareMatrix.hpp"
60#include "math/Vector.hpp"
61#include "math/Vector3.hpp"
62#include "nonbonded/NonBondedInteraction.hpp"
63#include "utils/simError.h"
64
65namespace OpenMD::Utils {
66
67 template<typename T>
69 static_assert(std::is_default_constructible_v<T>,
70 "Accumulator type parameters must be default constructible.");
71
72 public:
73 void add(const T& val) {
74 Count_++;
75
76 Val_ = val;
77 Total_ += val;
78 Avg_ += (val - Avg_) / static_cast<RealType>(Count_);
79 Avg2_ += (val * val - Avg2_) / static_cast<RealType>(Count_);
80
81 if (Count_ <= 1) {
82 Max_ = val;
83 Min_ = val;
84 } else {
85 Max_ = val > Max_ ? val : Max_;
86 Min_ = val < Min_ ? val : Min_;
87 }
88 }
89
90 std::size_t getCount() const { return Count_; }
91
92 T getLastValue() const { return Val_; }
93
94 T getTotal() const {
95 assert(Count_ != 0);
96 return Total_;
97 }
98
99 RealType getMax() const {
100 static_assert(std::is_arithmetic<T>::value,
101 "getMax() requires a RealType Accumulator.");
102 assert(Count_ != 0);
103 return Max_;
104 }
105
106 RealType getMin() const {
107 static_assert(std::is_arithmetic<T>::value,
108 "getMin() requires a RealType Accumulator.");
109 assert(Count_ != 0);
110 return Min_;
111 }
112
113 RealType getAverage() const {
114 assert(Count_ != 0);
115 return Avg_;
116 }
117
118 RealType getVariance() const {
119 assert(Count_ != 0);
120 T var = (Avg2_ - Avg_ * Avg_);
121 if (var < 0) var = 0;
122
123 return var;
124 }
125
126 RealType getStdDev() const {
127 assert(Count_ != 0);
128 T sd = std::sqrt(this->getVariance());
129
130 return sd;
131 }
132
133 RealType get95percentConfidenceInterval() const {
134 assert(Count_ != 0);
135 T ci =
136 1.960 * this->getStdDev() / std::sqrt(static_cast<RealType>(Count_));
137
138 return ci;
139 }
140
141 private:
142 std::size_t Count_ {};
143 T Val_ {}, Total_ {};
144 RealType Max_ {}, Min_ {}, Avg_ {}, Avg2_ {};
145 };
146
147 // Specializations for commonly used Accumulator types
148 template<>
149 class Accumulator<std::vector<RealType>> {
150 public:
151 /* A flag specifying that a given bin is empty and should be ignored
152 during calls to add() */
153 constexpr static RealType BinEmptyFlag =
154 std::numeric_limits<RealType>::max();
155
156 void add(const std::vector<RealType>& val) {
157 if (val.empty() || (val.size() != Avg_.size() && !Avg_.empty())) {
158 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
159 "Size of vector passed to add() did not "
160 "match the size of the StaticAccumulator.");
161 painCave.isFatal = 1;
162 simError();
163 }
164
165 Count_++;
166
167 if (Avg_.empty()) {
168 Val_.resize(val.size());
169 Total_.resize(val.size());
170 Avg_.resize(val.size());
171 Avg2_.resize(val.size());
172 }
173
174 for (std::size_t i = 0; i < val.size(); i++) {
175 /* If our placeholder, BinEmptyFlag, is passed to add(), we should
176 not record data at the current index */
177 if (val[i] == BinEmptyFlag) continue;
178 Val_[i] = val[i];
179 Total_[i] += val[i];
180 Avg_[i] += (val[i] - Avg_[i]) / static_cast<RealType>(Count_);
181 Avg2_[i] +=
182 (val[i] * val[i] - Avg2_[i]) / static_cast<RealType>(Count_);
183 }
184 }
185
186 std::size_t getCount() const { return Count_; }
187
188 std::vector<RealType> getLastValue() const { return Val_; }
189
190 std::vector<RealType> getTotal() const { return Total_; }
191
192 std::vector<RealType> getAverage() const { return Avg_; }
193
194 std::vector<RealType> getVariance() const {
195 std::vector<RealType> var(Avg_.size());
196
197 for (std::size_t i = 0; i < Avg_.size(); i++) {
198 var[i] = (Avg2_[i] - Avg_[i] * Avg_[i]);
199 if (var[i] < 0) var[i] = 0;
200 }
201
202 return var;
203 }
204
205 std::vector<RealType> getStdDev() const {
206 std::vector<RealType> sd(Avg_.size());
207 std::vector<RealType> variance = this->getVariance();
208
209 for (std::size_t i = 0; i < variance.size(); i++) {
210 sd[i] = std::sqrt(variance[i]);
211 }
212
213 return sd;
214 }
215
216 std::vector<RealType> get95percentConfidenceInterval() const {
217 std::vector<RealType> ci(Avg_.size());
218 std::vector<RealType> stdDev = this->getStdDev();
219
220 for (std::size_t i = 0; i < stdDev.size(); i++) {
221 ci[i] = 1.960 * stdDev[i] / std::sqrt(static_cast<RealType>(Count_));
222 }
223
224 return ci;
225 }
226
227 private:
228 std::size_t Count_ {};
229 std::vector<RealType> Val_ {}, Total_ {}, Avg_ {}, Avg2_ {};
230 };
231
232 template<unsigned int Dim>
233 class Accumulator<Vector<RealType, Dim>> {
234 public:
235 void add(const Vector<RealType, Dim>& val) {
236 Count_++;
237
238 for (std::size_t i = 0; i < Dim; i++) {
239 Val_[i] = val[i];
240 Total_[i] += val[i];
241 Avg_[i] += (val[i] - Avg_[i]) / static_cast<RealType>(Count_);
242 Avg2_[i] +=
243 (val[i] * val[i] - Avg2_[i]) / static_cast<RealType>(Count_);
244 }
245 }
246
247 std::size_t getCount() const { return Count_; }
248
249 Vector<RealType, Dim> getLastValue() const { return Val_; }
250
251 Vector<RealType, Dim> getTotal() const {
252 assert(Count_ != 0);
253
254 return Total_;
255 }
256
257 Vector<RealType, Dim> getAverage() const {
258 assert(Count_ != 0);
259
260 return Avg_;
261 }
262
263 Vector<RealType, Dim> getVariance() const {
264 assert(Count_ != 0);
265
267
268 for (std::size_t i = 0; i < Dim; i++) {
269 var[i] = (Avg2_[i] - Avg_[i] * Avg_[i]);
270 if (var[i] < 0) var[i] = 0;
271 }
272
273 return var;
274 }
275
276 Vector<RealType, Dim> getStdDev() const {
277 assert(Count_ != 0);
278
280 Vector<RealType, Dim> variance = this->getVariance();
281
282 for (std::size_t i = 0; i < Dim; i++) {
283 sd[i] = std::sqrt(variance[i]);
284 }
285
286 return sd;
287 }
288
289 Vector<RealType, Dim> get95percentConfidenceInterval() const {
290 assert(Count_ != 0);
291
293 Vector<RealType, Dim> stdDev = this->getStdDev();
294
295 for (std::size_t i = 0; i < Dim; i++) {
296 ci[i] = 1.960 * stdDev[i] / std::sqrt(static_cast<RealType>(Count_));
297 }
298
299 return ci;
300 }
301
302 private:
303 std::size_t Count_ {};
304 Vector<RealType, Dim> Val_ {}, Total_ {}, Avg_ {}, Avg2_ {};
305 };
306
307 template<>
308 class Accumulator<Mat3x3d> {
309 public:
310 void add(const Mat3x3d& val) {
311 Count_++;
312
313 for (std::size_t i = 0; i < 3; i++) {
314 for (std::size_t j = 0; j < 3; j++) {
315 Val_(i, j) = val(i, j);
316 Total_(i, j) += val(i, j);
317 Avg_(i, j) +=
318 (val(i, j) - Avg_(i, j)) / static_cast<RealType>(Count_);
319 Avg2_(i, j) += (val(i, j) * val(i, j) - Avg2_(i, j)) /
320 static_cast<RealType>(Count_);
321 }
322 }
323 }
324
325 std::size_t getCount() const { return Count_; }
326
327 Mat3x3d getLastValue() const { return Val_; }
328
329 Mat3x3d getTotal() const {
330 assert(Count_ != 0);
331
332 return Total_;
333 }
334
335 Mat3x3d getAverage() const {
336 assert(Count_ != 0);
337
338 return Avg_;
339 }
340
341 Mat3x3d getVariance() const {
342 assert(Count_ != 0);
343
344 Mat3x3d var {};
345
346 for (std::size_t i = 0; i < 3; i++) {
347 for (std::size_t j = 0; j < 3; j++) {
348 var(i, j) = (Avg2_(i, j) - Avg_(i, j) * Avg_(i, j));
349 if (var(i, j) < 0) var(i, j) = 0;
350 }
351 }
352
353 return var;
354 }
355
356 Mat3x3d getStdDev() const {
357 assert(Count_ != 0);
358
359 Mat3x3d sd {};
360 Mat3x3d variance = this->getVariance();
361
362 for (std::size_t i = 0; i < 3; i++) {
363 for (std::size_t j = 0; j < 3; j++) {
364 sd(i, j) = std::sqrt(variance(i, j));
365 }
366 }
367
368 return sd;
369 }
370
371 Mat3x3d get95percentConfidenceInterval() const {
372 assert(Count_ != 0);
373
374 Mat3x3d ci {};
375 Mat3x3d stdDev = this->getStdDev();
376
377 for (std::size_t i = 0; i < 3; i++) {
378 for (std::size_t j = 0; j < 3; j++) {
379 ci(i, j) =
380 1.960 * stdDev(i, j) / std::sqrt(static_cast<RealType>(Count_));
381 }
382 }
383
384 return ci;
385 }
386
387 private:
388 std::size_t Count_ {};
389 Mat3x3d Val_ {}, Total_ {}, Avg_ {}, Avg2_ {};
390 };
391
392 // Type aliases for the most commonly used Accumulators
393 using RealAccumulator = Accumulator<RealType>;
394 using StdVectorAccumulator = Accumulator<std::vector<RealType>>;
395 using Vector3dAccumulator = Accumulator<Vector<RealType, 3>>;
396 using PotVecAccumulator =
398 using Mat3x3dAccumulator = Accumulator<Mat3x3d>;
399} // namespace OpenMD::Utils
400
401#endif // OPENMD_UTILS_STATICACCUMULATOR_HPP
Fix length vector class.
Definition Vector.hpp:81