OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
BlockSnapshotManager.cpp
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#include "brains/BlockSnapshotManager.hpp"
49
50#include <algorithm>
51#include <functional>
52#include <iostream>
53#include <string>
54
55#include "brains/SimInfo.hpp"
56#include "io/DumpReader.hpp"
57
58namespace OpenMD {
59
60 BlockSnapshotManager::BlockSnapshotManager(
61 SimInfo* info, const std::string& filename, int atomStorageLayout,
62 int rigidBodyStorageLayout, int cutoffGroupStorageLayout,
63 long long int memSize, int blockCapacity) :
64 SnapshotManager(atomStorageLayout, rigidBodyStorageLayout,
65 cutoffGroupStorageLayout),
66 blockCapacity_(blockCapacity), memSize_(memSize),
67 activeBlocks_(blockCapacity_, -1), activeRefCount_(blockCapacity_, 0) {
68 nAtoms_ = info->getNGlobalAtoms();
69 nRigidBodies_ = info->getNGlobalRigidBodies();
70 nCutoffGroups_ = info->getNCutoffGroups();
71 usePBC_ = info->getSimParams()->getUsePeriodicBoundaryConditions();
72
73 // eliminate suspect calls to figure out free memory:
74 // RealType physMem = physmem_total();
75 // RealType rssMem = residentMem();
76 // RealType avaliablePhysMem = physMem - rssMem;
77
78 int bytesPerAtom = DataStorage::getBytesPerStuntDouble(atomStorageLayout);
79 int bytesPerRigidBody =
80 DataStorage::getBytesPerStuntDouble(rigidBodyStorageLayout);
81 int bytesPerCutoffGroup =
82 DataStorage::getBytesPerStuntDouble(DataStorage::dslPosition);
83
84 int bytesPerFrameData = Snapshot::getFrameDataSize();
85 int bytesPerFrame =
86 nRigidBodies_ * bytesPerRigidBody + nAtoms_ * bytesPerAtom +
87 nCutoffGroups_ * bytesPerCutoffGroup + bytesPerFrameData;
88
89 // total number of frames that can fit in memory
90 // RealType frameCapacity = avaliablePhysMem / bytesPerFrame;
91 RealType frameCapacity = (RealType)memSize_ / (RealType)bytesPerFrame;
92
93 // number of frames in each block given the need to hold multiple blocks
94 // in memory at the same time:
95 nSnapshotPerBlock_ = int(frameCapacity) / blockCapacity_;
96 if (nSnapshotPerBlock_ <= 0) {
97 std::cerr << "not enough memory to hold two configs!\n";
98 }
99 reader_ = new DumpReader(info, filename);
100 nframes_ = reader_->getNFrames();
101 int nblocks = nframes_ / nSnapshotPerBlock_;
102 if (nframes_ % int(nSnapshotPerBlock_) != 0) { ++nblocks; }
103
104 for (int i = 0; i < nblocks; ++i) {
105 blocks_.push_back(
106 SnapshotBlock(i * nSnapshotPerBlock_, (i + 1) * nSnapshotPerBlock_));
107 }
108 // the last block may not have nSnapshotPerBlock frames, we need
109 // to consider this special situation
110 blocks_.back().second = nframes_;
111
112 snapshots_.insert(snapshots_.begin(), nframes_,
113 static_cast<Snapshot*>(NULL));
114
115 std::cout << "-----------------------------------------------------\n";
116 std::cout << "BlockSnapshotManager memory report:\n";
117 std::cout << "\n";
118 // std::cout << " Physical Memory available:\t" << (unsigned long)physMem
119 // << " bytes"
120 // <<std::endl;
121 // std::cout << " Resident Memory in use:\t" << (unsigned long)rssMem <<
122 // " bytes"
123 // <<std::endl; std::cout << "Memory available for OpenMD:\t" << (unsigned
124 // long)avaliablePhysMem << " bytes" <<std::endl;
125 std::cout << "Memory requested for OpenMD:\t" << (unsigned long)memSize_
126 << " bytes" << std::endl;
127 std::cout << " Bytes per FrameData:\t"
128 << (unsigned long)bytesPerFrameData << std::endl;
129 std::cout << " Bytes per Atom:\t" << (unsigned long)bytesPerAtom
130 << std::endl;
131 std::cout << " Bytes per RigidBody:\t"
132 << (unsigned long)bytesPerRigidBody << std::endl;
133 std::cout << " Bytes per Cutoff Group:\t"
134 << (unsigned long)bytesPerCutoffGroup << std::endl;
135 std::cout << " Bytes per Frame:\t"
136 << (unsigned long)bytesPerFrame << std::endl;
137 std::cout << " Frame Capacity:\t"
138 << (unsigned long)frameCapacity << std::endl;
139 std::cout << " Frames in trajectory:\t" << (unsigned long)nframes_
140 << std::endl;
141 std::cout << " Snapshots per Block:\t"
142 << (unsigned long)nSnapshotPerBlock_ << std::endl;
143 std::cout << " Total number of Blocks:\t" << (unsigned long)nblocks
144 << std::endl;
145 std::cout << "-----------------------------------------------------"
146 << std::endl;
147 }
148
149 BlockSnapshotManager::~BlockSnapshotManager() {
150 currentSnapshot_ = NULL;
151 previousSnapshot_ = NULL;
152
153 delete reader_;
154
155 std::vector<int>::iterator i;
156 for (i = activeBlocks_.begin(); i != activeBlocks_.end(); ++i) {
157 if (*i != -1) { unloadBlock(*i); }
158 }
159 }
160
161 Snapshot* BlockSnapshotManager::getSnapshot(int id) {
162 currentSnapshot_ = snapshots_[id];
163 return snapshots_[id];
164 }
165
166 int BlockSnapshotManager::getNActiveBlocks() {
167 return std::count_if(activeBlocks_.begin(), activeBlocks_.end(),
168 [](int val) { return val != -1; });
169 }
170
171 bool BlockSnapshotManager::loadBlock(int block) {
172 std::vector<int>::iterator i = findActiveBlock(block);
173 bool loadSuccess(false);
174 if (i != activeBlocks_.end()) {
175 // If the block is already in memory, just increase the
176 // reference count:
177 ++activeRefCount_[i - activeBlocks_.begin()];
178 loadSuccess = true;
179 } else if (getNActiveBlocks() < blockCapacity_) {
180 // If the number of active blocks is less than the block
181 // capacity, just load the block:
182 internalLoad(block);
183 loadSuccess = true;
184 } else if (hasZeroRefBlock()) {
185 // If we have already reached the block capacity, we need to
186 // unload a block with 0 references:
187 int zeroRefBlock = getFirstZeroRefBlock();
188 assert(zeroRefBlock != -1);
189 internalUnload(zeroRefBlock);
190 internalLoad(block);
191 } else {
192 // We have reached capacity and all blocks in memory are have
193 // non-zero references:
194 loadSuccess = false;
195 }
196 return loadSuccess;
197 }
198
199 bool BlockSnapshotManager::unloadBlock(int block) {
200 bool unloadSuccess;
201 std::vector<int>::iterator i = findActiveBlock(block);
202
203 if (i != activeBlocks_.end()) {
204 --activeRefCount_[i - activeBlocks_.begin()];
205 if (activeRefCount_[i - activeBlocks_.begin()] < 0) {
206 // in case, unloadBlock called multiple times
207 activeRefCount_[i - activeBlocks_.begin()] = 0;
208 }
209
210 if (activeRefCount_[i - activeBlocks_.begin()] == 0) {
211 internalUnload(block);
212 }
213
214 unloadSuccess = true;
215 } else {
216 unloadSuccess = false;
217 }
218
219 return unloadSuccess;
220 }
221
222 void BlockSnapshotManager::internalLoad(int block) {
223 for (int i = blocks_[block].first; i < blocks_[block].second; ++i) {
224 snapshots_[i] = loadFrame(i);
225 }
226
227 std::vector<int>::iterator j;
228 j = std::find(activeBlocks_.begin(), activeBlocks_.end(), -1);
229 assert(j != activeBlocks_.end());
230 *j = block;
231 ++activeRefCount_[j - activeBlocks_.begin()];
232 }
233
234 void BlockSnapshotManager::internalUnload(int block) {
235 for (int i = blocks_[block].first; i < blocks_[block].second; ++i) {
236 delete snapshots_[i];
237 snapshots_[i] = NULL;
238 }
239 std::vector<int>::iterator j;
240 j = std::find(activeBlocks_.begin(), activeBlocks_.end(), block);
241 assert(j != activeBlocks_.end());
242 *j = -1;
243 }
244
245 bool BlockSnapshotManager::hasZeroRefBlock() {
246 return std::find(activeRefCount_.begin(), activeRefCount_.end(), 0) !=
247 activeRefCount_.end() ?
248 true :
249 false;
250 }
251
252 int BlockSnapshotManager::getFirstZeroRefBlock() {
253 std::vector<int>::iterator i =
254 std::find(activeRefCount_.begin(), activeRefCount_.end(), 0);
255 return i != activeRefCount_.end() ?
256 activeBlocks_[i - activeRefCount_.begin()] :
257 -1;
258 }
259
260 std::vector<int> BlockSnapshotManager::getActiveBlocks() {
261 std::vector<int> result;
262 std::copy_if(
263 activeBlocks_.begin(), activeBlocks_.end(), std::back_inserter(result),
264 std::bind(std::not_equal_to<int>(), std::placeholders::_1, -1));
265 return result;
266 }
267
268 Snapshot* BlockSnapshotManager::loadFrame(int frame) {
269 Snapshot* snapshot = new Snapshot(
270 nAtoms_, nRigidBodies_, nCutoffGroups_, getAtomStorageLayout(),
271 getRigidBodyStorageLayout(), getCutoffGroupStorageLayout(), usePBC_);
272 snapshot->setID(frame);
273 snapshot->clearDerivedProperties();
274
275 currentSnapshot_ = snapshot;
276 reader_->readFrame(frame);
277
278 return snapshot;
279 }
280
281 int BlockSnapshotManager::getNFrames() { return reader_->getNFrames(); }
282
283 void BlockSnapshotManager::needCOMprops(bool ncp) {
284 reader_->setNeedCOMprops(ncp);
285 }
286
287} // namespace OpenMD
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Definition SimInfo.hpp:96
SnapshotManager class is an abstract class which maintains a series of snapshots.
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.