#pragma once #include #include #include #include #include #include #include #include #include #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 _memoryA; std::vector _memoryB; gsl::multi_span _model; gsl::multi_span _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(_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{ // _noCols + 1, // // _noRows, // //}; // const auto& distribs = std::array{ // MPI_DISTRIBUTE_BLOCK, // // MPI_DISTRIBUTE_BLOCK // //}; // const auto& dargs = std::array{ // MPI_DISTRIBUTE_DFLT_DARG, // // MPI_DISTRIBUTE_DFLT_DARG // //}; // const auto& psizes = std::array{ // 2, // // 4 // //}; //// const auto& noDims = 1; //// const auto& gsizes = std::array{_noCols}; //// const auto& distribs = std::array{MPI_DISTRIBUTE_BLOCK}; //// const auto& dargs = std::array{MPI_DISTRIBUTE_DFLT_DARG}; //// const auto& psizes = std::array{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) { out << '"'; 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); } void simulateStep() { _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 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); } };