#include "MpiWireworld.hpp" #include #include #include #include #include #include #include "gsl/gsl" #include "FileIO.hpp" #include "State.hpp" #include "Tile.hpp" #include "Util.hpp" void MpiWireworld::processCell(std::size_t x, std::size_t y) { const auto& _model = _tile.model(); auto& _nextModel = _tile.nextModel(); const auto currentState = _model[y][x]; _nextModel[y][x] = [&]() { switch (currentState) { case State::ElectronHead: return State::ElectronTail; break; case State::ElectronTail: return State::Conductor; break; case State::Conductor: { const std::array mooreNeighborhood = { _model[y - 1][x - 1], // _model[y + 0][x - 1], // _model[y + 1][x - 1], // _model[y - 1][x + 0], // _model[y + 1][x + 0], // _model[y - 1][x + 1], // _model[y + 0][x + 1], // _model[y + 1][x + 1] // }; const auto headCount = std::count(std::begin(mooreNeighborhood), std::end(mooreNeighborhood), State::ElectronHead); 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.Grid, _tile.tileSize()) { _comm.Communicate(_tile.model()); } std::ostream& operator<<(std::ostream& out, const MpiWireworld& g) { // for now, put only our local tile 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 for (std::size_t x{1}; x <= _tileSize.Cols; ++x) { const auto y = 1; processCell(x, y); } // left and right for (std::size_t y{2}; y < _tileSize.Rows; ++y) { const auto x1 = 1; const auto x2 = _tileSize.Cols; processCell(x1, y); processCell(x2, y); } // bottom for (std::size_t x{1}; x <= _tileSize.Cols; ++x) { const auto y = _tileSize.Rows; processCell(x, y); } // start communication of border while processing the core auto req = _comm.AsyncCommunicate(_nextModel); /// core for (std::size_t y{2}; y < _tileSize.Rows; ++y) { for (std::size_t x{2}; x < _tileSize.Cols; ++x) { processCell(x, y); } } req.Wait(); std::swap(_model, _nextModel); }