Newer
Older
#include "MpiWireworld.hpp"
#include <algorithm>
#include <array>
#include <iostream>
#include <mpi.h>
#include <string>
#include <vector>
#include "FileIO.hpp"
#include "Tile.hpp"
#include "Util.hpp"
void MpiWireworld::processArea(Coord start, Size size) {
auto& _model = _tile.model();
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
const auto modelWidth = _tile.modelWidth();
// std::size_t is unsigned. modulo arithmetics is used for calculating the
// index
const std::size_t leftOffset = -1;
const std::size_t rightOffset = 1;
const std::size_t downOffset = modelWidth;
const std::size_t upOffset = -downOffset;
for (std::size_t y{start.Y}; y < start.Y + size.Rows; ++y) {
for (std::size_t x{start.X}; x < start.X + size.Cols; ++x) {
const auto idx = y * modelWidth + x;
const auto currentState = _model[idx];
_nextModel[idx] = [&]() {
switch (currentState) {
case State::ElectronHead:
return State::ElectronTail;
break;
case State::ElectronTail:
return State::Conductor;
break;
case State::Conductor: {
const auto isHead = [&](std::size_t idx) {
return _model[idx] == State::ElectronHead ? 1 : 0;
};
const auto headCount =
isHead(idx + leftOffset + upOffset) + //
isHead(idx + upOffset) + //
isHead(idx + rightOffset + upOffset) + //
isHead(idx + leftOffset) + //
isHead(idx + rightOffset) + //
isHead(idx + leftOffset + downOffset) + //
isHead(idx + downOffset) + //
isHead(idx + rightOffset + downOffset); //
return (1 == headCount || headCount == 2)
? State::ElectronHead
: State::Conductor;
} break;
default:
return currentState;
break;
}
}();
}
MpiWireworld::MpiWireworld(const MpiEnvironment& env, const Configuration& cfg)
: _env(env), _cfg(cfg), _tile(Tile::Read(cfg, env)),
_comm(env, cfg.CommMode, cfg.Procs, _tile.tileSize()) {
_comm.Communicate(_tile.model());
}
std::ostream& operator<<(std::ostream& out, const MpiWireworld& g) {
out << g._tile;
return out;
}
void MpiWireworld::write() const { _tile.write(); }
void MpiWireworld::simulateStep() {
auto& _model = _tile.model();
auto& _nextModel = _tile.nextModel();
const auto _tileSize = _tile.tileSize();
//// compute the border area first, then comm
//// and compute the core async
/// border area
// top
processArea({1, 2}, {1, _tileSize.Rows - 2});
processArea({_tileSize.Cols, 2}, {1, _tileSize.Rows - 2});
processArea({1, _tileSize.Rows}, {_tileSize.Cols, 1});
// start communication of border while processing the core
auto req = _comm.AsyncCommunicate(_nextModel);
processArea({2, 2}, {_tileSize.Cols - 2, _tileSize.Rows - 2});
req.Wait();
std::swap(_model, _nextModel);
}