#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(Tile::Read(cfg, env)), _comm(env, cfg.Grid, _tile.tileSize()) {} 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(); _comm.Communicate(_model); // compute the border area first, then comm // and compute the rest async for (std::size_t y{1}; y <= _tileSize.Rows; ++y) { for (std::size_t x{1}; x <= _tileSize.Cols; ++x) { 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; } } std::swap(_model, _nextModel); } };