#include "MpiWireworld.hpp" #include #include #include #include #include #include #include #include "CommunicatorFactory.hpp" #include "FileIO.hpp" #include "State.hpp" #include "Tile.hpp" #include "Util.hpp" void MpiWireworld::processArea(Coord start, Size size) { auto& model_ = tile_.model(); auto& nextModel_ = tile_.nextModel(); const auto modelWidth = tile_.modelWidth(); // std::size_t is unsigned. modulo arithmetics is used for calculating the // index const std::size_t leftOffset = std::numeric_limits::max(); // -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; case State::ElectronTail: return State::Conductor; case State::Conductor: { const auto isHead = [&](std::size_t i) { return model_[i] == 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; }; default: return currentState; } }(); } } } MpiWireworld::MpiWireworld(const MpiEnvironment& env, const Configuration& cfg) : tile_(Tile::Read(cfg, env)), comm_(CommunicatorFactory::Create(cfg, tile_, env)) { 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 processArea({1, 1}, {tileSize_.Cols, 1}); // left and right processArea({1, 2}, {1, tileSize_.Rows - 2}); processArea({tileSize_.Cols, 2}, {1, tileSize_.Rows - 2}); // bottom processArea({1, tileSize_.Rows}, {tileSize_.Cols, 1}); // start communication of border while processing the core auto req = comm_->AsyncCommunicate(nextModel_); /// core processArea({2, 2}, {tileSize_.Cols - 2, tileSize_.Rows - 2}); req.Wait(); std::swap(model_, nextModel_); }