Skip to content
MpiWireworld.hpp 5.37 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;
	Size _tileSize;
	std::vector<State> _memoryA;
	std::vector<State> _memoryB;
	gsl::multi_span<State, -1, -1> _model;
	gsl::multi_span<State, -1, -1> _nextModel;
	Communicator _comm;
  public:
	auto getTileSize() { return _tileSize; }
	MpiWireworld(const MpiEnvironment& env, const Configuration& cfg)
	    : _env(env), _cfg(cfg) {
		const auto& gridSize = Size{cfg.GridColumns, cfg.GridRows};
		std::ifstream input(cfg.InputFilePath);
		const auto& _globalSize = FileIO::ReadHeader(input);
		_tileSize = FileIO::GetTileSize(_globalSize, gridSize);

		_memoryA.resize((_tileSize.Cols + 2) * (_tileSize.Rows + 2));
		_memoryB.resize((_tileSize.Cols + 2) * (_tileSize.Rows + 2));
		_model =
		    gsl::as_multi_span(_memoryA.data(), gsl::dim(_tileSize.Rows + 2),
		                       gsl::dim(_tileSize.Cols + 2));
		_nextModel =
		    gsl::as_multi_span(_memoryB.data(), gsl::dim(_tileSize.Rows + 2),
		                       gsl::dim(_tileSize.Cols + 2));

		FileIO::ReadTile(
		    input, _globalSize, gridSize, _env.worldRank(),
		    gsl::span<State>(_memoryA.data() + _tileSize.Cols + 2 + 1,
		                     _memoryA.size() - 1),
		    _tileSize.Cols + 2);

		/*

		// Trying to acomplish this with MPI


		// if (env.isMaster()) {
		//	std::cout << "noCols: " << _noCols << '\n';
		//	std::cout << "noRows: " << _noRows << '\n';
		//}

		// const auto& noDims = 2;

		// const auto& gsizes = std::array<int, 2>{
		//	_noCols + 1,  //
		//    _noRows, //
		//};

		// const auto& distribs = std::array<int, 2>{
		//    MPI_DISTRIBUTE_BLOCK, //
		//    MPI_DISTRIBUTE_BLOCK  //
		//};

		// const auto& dargs = std::array<int, 2>{
		//    MPI_DISTRIBUTE_DFLT_DARG, //
		//    MPI_DISTRIBUTE_DFLT_DARG  //
		//};

		// const auto& psizes = std::array<int, 2>{
		//    2, //
		//    4  //
		//};

		//// const auto& noDims = 1;

		//// const auto& gsizes = std::array<int, 1>{_noCols};

		//// const auto& distribs = std::array<int, 1>{MPI_DISTRIBUTE_BLOCK};

		//// const auto& dargs = std::array<int, 1>{MPI_DISTRIBUTE_DFLT_DARG};

		//// const auto& psizes = std::array<int, 1>{8};

		////MPI_Datatatype tiletype;
		////int global_sizes[2] = { _noCols + 1, _noRows };
		////int tile_sizes[2] = { 10, 5 };
		////int tile_start[2] = { }

		////MPI_Type_create_subarray(2, global_sizes, tile_sizes, )

		// MPI_Datatype tiletype;
		////MPI_Datatype linetype;
		////MPI_Datatype linetype_ext;

		////MPI_Type_contiguous(_noCols, MPI_CHAR, &linetype);
		////MPI_Type_create_resized(linetype, 0, _noCols + 1, &linetype_ext);
		////MPI_Type_commit(&linetype_ext);
		////MPI_Type_free(&linetype);

		//
		// MPI_Type_create_darray(env.worldSize(), env.worldRank(), noDims,
		//                       gsizes.data(), distribs.data(), dargs.data(),
		//                       psizes.data(), MPI_ORDER_C, MPI_CHAR,
		//                       &tiletype);
		// MPI_Type_commit(&tiletype);
		// int tiletypeSize;
		// MPI_Type_size(tiletype, &tiletypeSize);

		// if (env.isMaster())
		//	std::cout << "tiletypeSize: " << tiletypeSize << '\n';

		// MPI_File fh;
		// MPI_File_open(MPI_COMM_WORLD, path.c_str(), MPI_MODE_RDONLY,
		//              MPI_INFO_NULL, &fh);
		// MPI_File_set_view(fh, _headerSize, MPI_CHAR, MPI_CHAR, "native",
		//                  MPI_INFO_NULL);

		// const auto& typeCols = 10; // how to get those?
		// const auto& typeRows = 5;



		MPI_File_read_all(fh, buf.data(), 1, tiletype, MPI_STATUS_IGNORE);

		MPI_File_close(&fh);

		std::replace(std::begin(buf), std::end(buf), '\n', 'L');

		*/
		_comm = Communicator{env, gridSize, _tileSize};
	}

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

	void Communicate() { _comm.Communicate(_model); }

		_comm.Communicate(_model);
		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);
	}
};