#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; public: MpiWireworld(const MpiEnvironment& env, const Configuration& cfg) : _env(env), _cfg(cfg), _tile(cfg, env) { _comm = Communicator{ env, {cfg.GridColumns, cfg.GridRows}, _tile.tileSize()}; } friend std::ostream& operator<<(std::ostream& out, const MpiWireworld& g) { for (std::size_t x{1}; x <= g._tile.tileSize().Rows; ++x) { out << '"'; for (std::size_t y{1}; y <= g._tile.tileSize().Cols; ++y) { out << to_integral(g._tile.model()[x][y]); } out << "\"\n"; } return out; } void simulateStep() { auto& _model = _tile.model(); auto& _nextModel = _tile.nextModel(); const auto& _tileSize = _tile.tileSize(); _comm.Communicate(_model); // compute the border area first, then comm // and compute the rest async for (std::size_t x{1}; x <= _tileSize.Rows; ++x) { for (std::size_t y{1}; y <= _tileSize.Cols; ++y) { auto nextState = _model[x][y]; switch (_model[x][y]) { case State::ElectronHead: nextState = State::ElectronTail; break; case State::ElectronTail: nextState = State::Conductor; break; case State::Conductor: { const std::array mooreNeighborhood = { _model[x - 1][y - 1], // _model[x + 0][y - 1], // _model[x + 1][y - 1], // _model[x - 1][y + 0], // _model[x + 1][y + 0], // _model[x - 1][y + 1], // _model[x + 0][y + 1], // _model[x + 1][y + 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[x][y] = nextState; } } std::swap(_model, _nextModel); } };