Newer
Older
#include "MpiWireworld.hpp"
#include <algorithm>
#include <array>
#include <iostream>
Thomas Steinreiter
committed
#include <limits>
#include <mpi.h>
#include <string>
#include <vector>
#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<std::size_t>::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: {
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;
}
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) {
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});
processArea({1, 2}, {1, tileSize_.Rows - 2});
processArea({tileSize_.Cols, 2}, {1, tileSize_.Rows - 2});
processArea({1, tileSize_.Rows}, {tileSize_.Cols, 1});
// start communication of border while processing the core
auto req = comm_->AsyncCommunicate(nextModel_);
processArea({2, 2}, {tileSize_.Cols - 2, tileSize_.Rows - 2});