Skip to content
MpiWireworld.hpp 3.17 KiB
Newer Older
#pragma once

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

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

#include "Communicator.hpp"
#include "FileIO.hpp"
#include "MpiEnvironment.hpp"
#include "Util.hpp"
#include "state.hpp"

class MpiWireworld {
	const MpiEnvironment& _env;
	const Configuration& _cfg;
	Communicator _comm;
	void 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;
	}

  public:
	MpiWireworld(const MpiEnvironment& env, const Configuration& cfg)
	    : _env(env), _cfg(cfg), _tile(Tile::Read(cfg, env)),
	      _comm(env, cfg.Grid, _tile.tileSize()) {
		// for (std::size_t y{1}; y <= _tile.tileSize().Rows; ++y) {
		//	for (std::size_t x{1}; x <= _tile.tileSize().Cols; ++x) {
		//		_idxs.push_back({x, y});
		//	}
		//}
		_comm.Communicate(_tile.model());
	}

	friend std::ostream& operator<<(std::ostream& out, const MpiWireworld& g) {
		// for now, print the own tile
		out << g._tile;
	void write() const { _tile.write(); }
		auto& _model = _tile.model();
		auto& _nextModel = _tile.nextModel();
Thomas Steinreiter's avatar
Thomas Steinreiter committed
		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);
	}
};