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