#pragma once #include #include #include #include #include #include #include #include #include #include "gsl/multi_span" #include "gsl/span" #include "Communicator.hpp" #include "FileIO.hpp" #include "MpiEnvironment.hpp" #include "Tile.hpp" #include "Util.hpp" #include "state.hpp" class MpiWireworld { const MpiEnvironment& _env; const Configuration& _cfg; Tile _tile; Communicator _comm; void processCell(std::size_t x, std::size_t y) { const auto& _model = _tile.model(); auto& _nextModel = _tile.nextModel(); auto nextState = _model[y][x]; switch (_model[y][x]) { case State::ElectronHead: nextState = State::ElectronTail; break; case State::ElectronTail: nextState = 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); nextState = (1 == headCount || headCount == 2) ? State::ElectronHead : State::Conductor; } break; default: break; } _nextModel[y][x] = nextState; } public: MpiWireworld(const MpiEnvironment& env, const Configuration& cfg) : _env(env), _cfg(cfg), _tile(Tile::Read(cfg, env)), _comm(env, cfg.Grid, _tile.tileSize()) { // for (std::size_t y{1}; y <= _tile.tileSize().Rows; ++y) { // for (std::size_t x{1}; x <= _tile.tileSize().Cols; ++x) { // _idxs.push_back({x, y}); // } //} _comm.Communicate(_tile.model()); } friend std::ostream& operator<<(std::ostream& out, const MpiWireworld& g) { // for now, print the own tile out << g._tile; return out; } void write() const { _tile.write(); } void 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(); //_comm.Communicate(_model); // for (std::size_t y{1}; y <= _tileSize.Rows; ++y) { // for (std::size_t x{1}; x <= _tileSize.Cols; ++x) { // processCell(x, y); // } //} std::swap(_model, _nextModel); } };