ls1-MarDyn
ls1-MarDyn molecular dynamics code
MidpointTraversal.h
1/*
2 * MidpointTraversal.h
3 *
4 * Created on: 06.07.2017
5 * Author: sascha
6 */
7
8#ifndef SRC_PARTICLECONTAINER_LINKEDCELLTRAVERSALS_MIDPOINTTRAVERSAL_H_
9#define SRC_PARTICLECONTAINER_LINKEDCELLTRAVERSALS_MIDPOINTTRAVERSAL_H_
10
11#include "particleContainer/LinkedCellTraversals/CellPairTraversals.h"
12#include <array>
13
15};
16
17template <class CellTemplate>
18class MidpointTraversal : public CellPairTraversals<CellTemplate>{
19public:
20 MidpointTraversal(std::vector<CellTemplate>& cells, const std::array<unsigned long, 3>& dims):
22 fillArrays(); // Array initialization could be done directly but GCC 4.9 doesn't like it
23 computeOffsets3D(); // >= C++14 this could be constexpr
24 computeOffsets();
25 }
26 virtual ~~MidpointTraversal() {}
27
31 virtual void rebuild(std::vector<CellTemplate> &cells,
32 const std::array<unsigned long, 3> &dims, double cellLength[3], double cutoff, CellPairTraversalData *data) override {
33 CellPairTraversals<CellTemplate>::rebuild(cells, dims, cellLength, cutoff, data);
34 computeOffsets();
35
36 _innerMostCellIndices.clear();
37 _notInnerMostCellIndices.clear();
38
39 auto maxIndex = 1;
40 for (auto d : dims)
41 maxIndex *= d;
42
43 for (auto i = 0; i < maxIndex; ++i) {
44 if (this->_cells->at(i).isInnerMostCell()){
45 _innerMostCellIndices.push_back(i);
46 } else {
47 _notInnerMostCellIndices.push_back(i);
48 }
49 }
50 }
51
52 virtual void traverseCellPairs(CellProcessor& cellProcessor) override;
53 virtual void traverseCellPairsOuter(CellProcessor& cellProcessor) override;
54 virtual void traverseCellPairsInner(CellProcessor& cellProcessor, unsigned stage, unsigned stageCount) override;
55
56 // Midpoint traversal requires force exchange
57 virtual bool requiresForceExchange() const override {return true;}
58 // Midpoint supports cell sizes down to cutoff/2
59 virtual unsigned maxCellsInCutoff() const override {return 2;}
60
61protected:
62 virtual void processBaseCell(CellProcessor& cellProcessor, unsigned long baseIndex) const;
63
64 // All pairs that have to be processed when calculating the forces (excluding self)
65 std::array<std::pair<long, long>, 62> _cellPairOffsets;
66 std::array<std::pair<std::array<long, 3>, std::array<long, 3>>, 62> _offsets3D;
67
68
69private:
70
71 void computeOffsets();
72 void computeOffsets3D(); // This could be changed to constexpr in C++14
73 void fillArrays();
74
75 void pairOriginWithForwardNeighbors(int& index);
76 void pairCellsWithPlane(std::array<long, 3>& cc,
77 std::array<long, 3>& oc, int& index);
78 void pairCellsWithAdjacentCorners(std::array<long, 3>& ce,
79 std::array<long, 3>& oe, int& index);
80
81 // Offsets of all faces of the surrounding cube. Opposite sides are (i+3)%6
82 std::array<std::array<long, 3>, 6> _faces;
83
84 // Offsets of all edges of the surrounding cube. Opposite sides are (i+6)%12
85 std::array<std::array<long, 3>, 12> _edges;
86
87 // Offsets of all corners of the surrounding cube. Opposite sides are (i+4)%8
88 std::array<std::array<long, 3>, 8> _corners;
89
90 std::vector<unsigned long> _innerMostCellIndices;
91 std::vector<unsigned long> _notInnerMostCellIndices;
92};
93
94template<class CellTemplate>
96 // Faces
97 _faces[0] = { 1, 0, 0};
98 _faces[1] = { 0, 1, 0};
99 _faces[2] = { 0, 0, 1};
100 // Mirrored at origin
101 _faces[3] = {-1, 0, 0};
102 _faces[4] = { 0,-1, 0};
103 _faces[5] = { 0, 0,-1};
104
105 // Edges
106 _edges[0] = { 1, 1, 0};
107 _edges[1] = { 1, 0, 1};
108 _edges[2] = { 0, 1, 1};
109 _edges[3] = {-1, 1, 0};
110 _edges[4] = {-1, 0, 1};
111 _edges[5] = { 0,-1, 1};
112 // Mirrored at origin
113 _edges[6] = {-1,-1, 0};
114 _edges[7] = {-1, 0,-1};
115 _edges[8] = { 0,-1,-1};
116 _edges[9] = { 1,-1, 0};
117 _edges[10] = { 1, 0,-1};
118 _edges[11] = { 0, 1,-1};
119
120 // Corners
121 _corners[0] = { 1, 1, 1};
122 _corners[1] = { 1, 1,-1};
123 _corners[2] = { 1,-1, 1};
124 _corners[3] = { 1,-1,-1};
125 // Mirrored at origin
126 _corners[4] = {-1,-1,-1};
127 _corners[5] = {-1,-1, 1};
128 _corners[6] = {-1, 1,-1};
129 _corners[7] = {-1, 1, 1};
130}
131
132template<class CellTemplate>
134
135 // Next free index of the offsets array
136 int index = 0;
137
138 // ----------------------------------------------------
139 // Opposite cells with midpoint in origin
140 // Opposite cells are set up to have index ((i+(n/2)) % n)
141 // ----------------------------------------------------
142
143 // process only half of the faces to get no pair twice
144 for(int i=0; i<3; ++i){ // faces
145 int j = (i+3)%6;
146 _offsets3D[index++] = make_pair(_faces[i], _faces[j]);
147 }
148 // process only half of the edges to get no pair twice
149 for(int i=0; i<6; ++i){ // edges
150 int j = (i+6)%12;
151 _offsets3D[index++] = make_pair(_edges[i], _edges[j]);
152 }
153 // process only half of the corners to get no pair twice
154 for(int i=0; i<4; ++i){ // corners
155 int j = (i+4)%8;
156 _offsets3D[index++] = make_pair(_corners[i], _corners[j]);
157 }
158
159 mardyn_assert(index == 13);
160
161 // ----------------------------------------------------
162 // Forward neighbors of origin (similar to half shell)
163 // ----------------------------------------------------
164
165 pairOriginWithForwardNeighbors(index);
166
167 mardyn_assert(index == 13+13);
168
169
170 // ----------------------------------------------------
171 // 'Cone' for half the faces
172 // ----------------------------------------------------
173 for(int i=0; i<3; ++i){
174 auto oc = _faces[(i+3)%6]; // opposite center
175 auto cc = _faces[i]; // current center
176
177 // Create pairs for each pair cc <--> oc + offset where offset is not in the direction of [CC Origin OC]
178 // Therefore with every cell (except OC) in the plane with normal vector [CC Origin OC] that contains OC.
179 pairCellsWithPlane(cc, oc, index);
180 }
181
182 mardyn_assert(index == 13+13+24);
183
184 // ----------------------------------------------------
185 // 'Cone' for half the edges
186 // ----------------------------------------------------
187 for(int i=0; i<6; ++i){
188 auto oe = _edges[(i+6)%12]; // opposite edge
189 auto ce = _edges[i]; // current edge
190
191 // Create pairs for each pair ce <--> (corners adjacent to oe)
192 pairCellsWithAdjacentCorners(ce, oe, index);
193
194 }
195
196 // We need exactly 62 cell offset pairs
197 mardyn_assert(index == 13+13+24+12);
198}
199
200template<class CellTemplate>
202 using threeDimensionalMapping::threeToOneD;
203
204 // Dim array is int but we need it as long for some reason (copied from C08BasedTraversal)
205 std::array<long, 3> dims;
206 for (int d = 0; d < 3; ++d) {
207 dims[d] = static_cast<long>(this->_dims[d]);
208 }
209
210 for(unsigned int i=0; i<_offsets3D.size(); ++i){
211
212 auto a = _offsets3D[i].first;
213 auto b = _offsets3D[i].second;
214
215 auto ax = std::get<0>(a);
216 auto ay = std::get<1>(a);
217 auto az = std::get<2>(a);
218
219 auto bx = std::get<0>(b);
220 auto by = std::get<1>(b);
221 auto bz = std::get<2>(b);
222
223 mardyn_assert((abs(ax) <= 1) && (abs(ay) <= 1) && (abs(az) <= 1));
224 mardyn_assert((abs(bx) <= 1) && (abs(by) <= 1) && (abs(bz) <= 1));
225
226 // convert 3d index to 1d
227 auto aIndex = threeToOneD(ax, ay, az, dims);
228 auto bIndex = threeToOneD(bx, by, bz, dims);
229
230 auto offsetPair = std::make_pair(aIndex, bIndex);
231
232 // store offset pair
233 _cellPairOffsets[i] = offsetPair;
234 }
235
236}
237
238template<class CellTemplate>
240 using std::make_pair;
241
242 std::array<long, 3> origin = {0l, 0l, 0l};
243
244 for(long y=-1; y<=1; ++y){ // 3 * 4
245 for(long x=-1; x<=1; ++x){ // 3
246 _offsets3D[index++] = make_pair(origin, std::array<long,3>{x, y, 1l});
247 }
248 // 1st
249 _offsets3D[index++] = make_pair(origin, std::array<long,3>{1l, y, 0l});
250 }
251
252 // 13th
253 _offsets3D[index++] = make_pair(origin, std::array<long,3>{0l, 1l, 0l});
254
255}
256
257template<class CellTemplate>
258void MidpointTraversal<CellTemplate>::pairCellsWithPlane(std::array<long, 3>& cc,
259 std::array<long, 3>& oc, int& index){
260 // Pairs the current cell (cc) with every cell next to oc except the origin.
261 for(int i=-1; i<=1; ++i){
262 for(int j=-1; j<=1; ++j){
263
264 // Skip pair cc <--> oc
265 if(i==0 && j==0) continue;
266
267 std::array<long, 3> cell;
268
269 if(std::get<0>(oc) == 0){
270 if(std::get<1>(oc) == 0){ // x and y are 0
271 // Center in +-z direction -> ring around oc in xy plane
272 cell = {i, j, std::get<2>(oc)};
273 } else { // x and z are 0
274 // Center in +-y direction -> ring around oc in xz plane
275 cell = {i, std::get<1>(oc), j};
276 }
277 } else { // y and z are 0
278 // Center in +-x direction -> ring around oc in yz plane
279 cell = {std::get<0>(oc), i, j};
280 }
281
282 _offsets3D[index++] = std::make_pair(cc, cell);
283 }
284 }
285}
286
287template<class CellTemplate>
289 std::array<long, 3>& oe, int& index){
290 // Pairs the current edge cell (ce) with both adjacent corners to oe
291 for(int i=-1; i<=1; i+=2){ // i=-1 and i=1
292
293 std::array<long, 3> cell;
294
295 if(std::get<0>(oe) == 0) { // x = 0
296 // Corners are oe with x=+-1
297 cell = {i, std::get<1>(oe), std::get<2>(oe)};
298 } else if(std::get<1>(oe) == 0) { // y = 0
299 // Corners are oe with y=+-1
300 cell = {std::get<0>(oe), i, std::get<2>(oe)};
301 } else { // z = 0
302 // Corners are oe with z=+-1
303 cell = {std::get<0>(oe), std::get<1>(oe), i};
304 }
305
306 _offsets3D[index++] = std::make_pair(ce, cell);
307 }
308}
309
310template<class CellTemplate>
312 unsigned long start = 0ul;
313 unsigned long end = this->_cells->size();
314 for(auto i = start; i<end; ++i){
315 processBaseCell(cellProcessor, i);
316 }
317}
318
319template<class CellTemplate>
321 //TODO ____ Test
322 for(unsigned long outerCellIndex : _notInnerMostCellIndices){
323 processBaseCell(cellProcessor, outerCellIndex);
324 }
325}
326
327template<class CellTemplate>
328void MidpointTraversal<CellTemplate>::traverseCellPairsInner(CellProcessor& cellProcessor, unsigned stage, unsigned stageCount){
329 //TODO ____ Test
330 unsigned long start = _innerMostCellIndices.size() * stage / stageCount;
331 unsigned long end = _innerMostCellIndices.size() * (stage+1) / stageCount;
332 for (unsigned long i = start; i < end; ++i) {
333 processBaseCell(cellProcessor, _innerMostCellIndices.at(i));
334 }
335}
336
337
338template<class CellTemplate>
339void MidpointTraversal<CellTemplate>::processBaseCell(CellProcessor& cellProcessor, unsigned long baseIndex) const{
340
341 CellTemplate& baseCell = this->_cells->at(baseIndex);
342
343 if(!baseCell.isHaloCell()) {
344
345 // Process all cell pairs for this cell
346 for(auto& current_pair : _cellPairOffsets){
347
348 unsigned long offset1 = current_pair.first;
349 unsigned long cellIndex1 = baseIndex + offset1;
350
351 unsigned long offset2 = current_pair.second;
352 unsigned long cellIndex2 = baseIndex + offset2;
353
354 CellTemplate& cell1 = this->_cells->at(cellIndex1);
355 CellTemplate& cell2 = this->_cells->at(cellIndex2);
356
357 const bool sumAllMacroscopic = true;
358 cellProcessor.processCellPair(cell1, cell2, sumAllMacroscopic);
359
360 }
361
362 // Process base cell itself
363 cellProcessor.processCell(baseCell);
364
365 }
366}
367
368#endif /* SRC_PARTICLECONTAINER_LINKEDCELLTRAVERSALS_MIDPOINTTRAVERSAL_H_ */
Definition: CellPairTraversals.h:21
virtual void rebuild(std::vector< CellTemplate > &cells, const std::array< unsigned long, 3 > &dims, double cellLength[3], double cutoff, CellPairTraversalData *data)
Definition: CellPairTraversals.h:32
Definition: CellProcessor.h:29
virtual void processCell(ParticleCell &cell)=0
virtual void processCellPair(ParticleCell &cell1, ParticleCell &cell2, bool sumAll=false)=0
Definition: MidpointTraversal.h:18
virtual void rebuild(std::vector< CellTemplate > &cells, const std::array< unsigned long, 3 > &dims, double cellLength[3], double cutoff, CellPairTraversalData *data) override
Definition: MidpointTraversal.h:31
Definition: CellPairTraversals.h:16
Definition: MidpointTraversal.h:14