Skip to content
MpiWireworld.cpp 2.74 KiB
Newer Older
#include "MpiWireworld.hpp"

#include <algorithm>
#include <array>
#include <iostream>
#include <mpi.h>
#include <string>
#include <vector>

#include "gsl/multi_span"
#include "gsl/span"

#include "FileIO.hpp"
#include "Tile.hpp"
#include "Util.hpp"
#include "state.hpp"

void MpiWireworld::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<State, 9> 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;
}

MpiWireworld::MpiWireworld(const MpiEnvironment& env, const Configuration& cfg)
    : _env(env), _cfg(cfg), _tile(Tile::Read(cfg, env)),
      _comm(env, cfg.Grid, _tile.tileSize()) {
	_comm.Communicate(_tile.model());
}

std::ostream& operator<<(std::ostream& out, const MpiWireworld& g) {
	// for now, print the own 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
	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);
}