Skip to content
MpiWireworld.hpp 2.32 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;
  public:
	MpiWireworld(const MpiEnvironment& env, const Configuration& cfg)
	    : _env(env), _cfg(cfg), _tile(cfg, env) {
		_comm = Communicator{
		    env, {cfg.GridColumns, cfg.GridRows}, _tile.tileSize()};
	}

	friend std::ostream& operator<<(std::ostream& out, const MpiWireworld& g) {
		for (std::size_t x{1}; x <= g._tile.tileSize().Rows; ++x) {
			for (std::size_t y{1}; y <= g._tile.tileSize().Cols; ++y) {
				out << to_integral(g._tile.model()[x][y]);
			}
			out << "\"\n";
		}
		return out;
	}

	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 x{1}; x <= _tileSize.Rows; ++x) {
			for (std::size_t y{1}; y <= _tileSize.Cols; ++y) {
				auto nextState = _model[x][y];
				switch (_model[x][y]) {
				case State::ElectronHead:
					nextState = State::ElectronTail;
					break;
				case State::ElectronTail:
					nextState = State::Conductor;
					break;
				case State::Conductor: {
					const std::array<State, 9> mooreNeighborhood = {
					    _model[x - 1][y - 1], //
					    _model[x + 0][y - 1], //
					    _model[x + 1][y - 1], //
					    _model[x - 1][y + 0], //
					    _model[x + 1][y + 0], //
					    _model[x - 1][y + 1], //
					    _model[x + 0][y + 1], //
					    _model[x + 1][y + 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[x][y] = nextState;
			}
		}
		std::swap(_model, _nextModel);
	}
};